Files
beep/includes/class-replies.php
T
Krystie b882092f5d Snapshot: Krystie uncommitted edits on sami-ahmed.net as of 2026-05-20 14:56 PT
These changes were applied DIRECTLY to the production cPanel server via
Fileman/save_file_content API calls between ~10:30 PT and 14:44 PT today.
None of them were committed or pushed at the time, violating the
Software → Repo rule (CLAUDE.md, added 2026-05-18).

Captured by Claude (VSCode-side) at Sami request so the changes can be
reviewed/cherry-picked instead of being silently lost.

Notable concerns:
- class-beep.php shrank from 3387 → 1395 bytes (likely truncation, not edit)
- beep.css shrank from 35431 → 22948 bytes (-12.5 KB; ~half the file gone)
- class-replies.php shrank from 8793 → 6406 bytes
- 3 new files (class-magic-links.php, class-follows.php, create_poll_tables.php)
  were created server-only with no repo presence

Source: live cPanel snapshot at /tmp/beep-snapshot-2026-05-20/
2026-05-20 15:12:41 -07:00

176 lines
6.3 KiB
PHP
Executable File

<?php
if (!defined('ABSPATH')) {
exit;
}
class Beep_Replies {
public static function init() {
add_action('rest_api_init', [__CLASS__, 'register_routes']);
}
public static function register_routes() {
register_rest_route('beep/v1', '/post', [
'methods' => 'POST',
'callback' => [__CLASS__, 'submit_beep'],
'permission_callback' => [Beep_Likes::class, 'can_interact'],
]);
register_rest_route('beep/v1', '/reply/(?P<id>\d+)', [
'methods' => 'POST',
'callback' => [__CLASS__, 'submit_reply'],
'permission_callback' => [Beep_Likes::class, 'can_interact'],
]);
register_rest_route('beep/v1', '/beep/(?P<id>\d+)', [
'methods' => 'DELETE',
'callback' => [__CLASS__, 'delete_beep'],
'permission_callback' => function ($req) {
return current_user_can('delete_post', (int) $req['id']);
},
]);
register_rest_route('beep/v1', '/reply/(?P<id>\d+)', [
'methods' => 'DELETE',
'callback' => [__CLASS__, 'delete_reply'],
'permission_callback' => function () {
return current_user_can('moderate_comments');
},
]);
}
public static function submit_beep($request) {
$content = trim((string) $request->get_param('content'));
$length = function_exists('mb_strlen') ? mb_strlen($content) : strlen($content);
if ($content === '' || $length > BEEP_CHAR_LIMIT) {
return new WP_Error('beep_invalid_content',
'Content must be 1-' . BEEP_CHAR_LIMIT . ' characters.',
['status' => 400]);
}
$post_id = wp_insert_post([
'post_type' => Beep_CPT::POST_TYPE,
'post_status' => 'publish',
'post_author' => get_current_user_id(),
'post_content' => wp_kses($content, []),
'post_title' => wp_trim_words($content, 8, '...'),
], true);
if (is_wp_error($post_id)) {
return $post_id;
}
return rest_ensure_response([
'id' => $post_id,
'html' => beep_render_post(get_post($post_id)),
]);
}
public static function submit_reply($request) {
$post_id = (int) $request['id'];
$content = trim((string) $request->get_param('content'));
$parent_id = (int) $request->get_param('parent');
$length = function_exists('mb_strlen') ? mb_strlen($content) : strlen($content);
if (get_post_type($post_id) !== Beep_CPT::POST_TYPE) {
return new WP_Error('beep_not_a_beep', 'Not a beep.', ['status' => 400]);
}
if ($content === '' || $length > BEEP_CHAR_LIMIT) {
return new WP_Error('beep_invalid_content',
'Reply must be 1-' . BEEP_CHAR_LIMIT . ' characters.',
['status' => 400]);
}
// Validate the parent comment belongs to this post if provided.
if ($parent_id > 0) {
$parent = get_comment($parent_id);
if (!$parent || (int) $parent->comment_post_ID !== $post_id) {
return new WP_Error('beep_bad_parent', 'Invalid parent.', ['status' => 400]);
}
}
$user = wp_get_current_user();
$approved = get_option('comment_moderation') ? 0 : 1;
if (get_option('comment_previously_approved')) {
$prev = get_comments([
'user_id' => $user->ID,
'status' => 'approve',
'count' => true,
]);
if (!$prev) {
$approved = 0;
}
}
$comment_id = wp_insert_comment([
'comment_post_ID' => $post_id,
'comment_author' => $user->display_name,
'comment_author_email' => $user->user_email,
'comment_author_url' => '',
'comment_content' => wp_kses($content, []),
'comment_type' => 'comment',
'comment_parent' => $parent_id,
'user_id' => $user->ID,
'comment_approved' => $approved,
]);
if (!$comment_id) {
return new WP_Error('beep_insert_failed', 'Reply could not be saved.', ['status' => 500]);
}
$comment = get_comment($comment_id);
$pending = ($comment->comment_approved == 0);
// Depth of this reply for client-side indenting.
$depth = 0;
$cur = $comment;
while ($cur && (int) $cur->comment_parent > 0 && $depth < 10) {
$cur = get_comment((int) $cur->comment_parent);
$depth++;
}
$can_interact = Beep_Likes::can_interact();
return rest_ensure_response([
'id' => $comment_id,
'parent' => (int) $comment->comment_parent,
'pending' => $pending,
'html' => $pending ? '' : beep_render_reply($comment, [], $depth, $post_id, $can_interact),
]);
}
public static function delete_beep($request) {
$post_id = (int) $request['id'];
if (get_post_type($post_id) !== Beep_CPT::POST_TYPE) {
return new WP_Error('beep_not_a_beep', 'Not a beep.', ['status' => 400]);
}
$deleted = wp_delete_post($post_id, true);
if (!$deleted) {
return new WP_Error('beep_delete_failed', 'Could not delete.', ['status' => 500]);
}
return rest_ensure_response(['deleted' => true]);
}
public static function delete_reply($request) {
$comment_id = (int) $request['id'];
$deleted = wp_delete_comment($comment_id, true);
if (!$deleted) {
return new WP_Error('beep_delete_failed', 'Could not delete.', ['status' => 500]);
}
return rest_ensure_response(['deleted' => true]);
}
public static function get_replies($post_id) {
return get_comments([
'post_id' => $post_id,
'status' => 'approve',
'order' => 'ASC',
'type' => 'comment',
]);
}
public static function reply_count($post_id) {
return (int) get_comments_number($post_id);
}
}