v1.9.0: reply composer media support (images, GIF, voice, quotes, polls on replies)
This commit is contained in:
+181
-6
@@ -15,6 +15,10 @@ class Beep_Media {
|
||||
private static $image_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
|
||||
private static $max_images = 4;
|
||||
private static $max_file_size = 10 * 1024 * 1024; // 10 MB
|
||||
private static $audio_types = ['audio/mpeg', 'audio/ogg', 'audio/wav', 'audio/webm', 'audio/mp4', 'audio/x-m4a'];
|
||||
private static $max_audio_size = 20 * 1024 * 1024; // 20 MB
|
||||
private static $video_types = ['video/mp4', 'video/webm', 'video/ogg', 'video/quicktime'];
|
||||
private static $max_video_size = 100 * 1024 * 1024; // 100 MB
|
||||
|
||||
public static function init() {}
|
||||
|
||||
@@ -217,9 +221,183 @@ class Beep_Media {
|
||||
delete_post_meta($post_id, self::META_KEY_IMAGES);
|
||||
delete_post_meta($post_id, self::META_KEY_VIDEO);
|
||||
}
|
||||
// Voice note support
|
||||
private static $audio_types = ['audio/mpeg', 'audio/ogg', 'audio/wav', 'audio/webm', 'audio/mp4', 'audio/x-m4a'];
|
||||
private static $max_audio_size = 20 * 1024 * 1024; // 20 MB
|
||||
|
||||
/* ============================================================
|
||||
* Parent-agnostic wrappers (v1.9.0)
|
||||
* $parent_type = 'post' (default) or 'comment'.
|
||||
* Routes to post_meta or comment_meta automatically.
|
||||
* ============================================================ */
|
||||
|
||||
public static function images_meta_key() {
|
||||
return self::META_KEY_IMAGES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the right meta storage for a parent (post or comment).
|
||||
*
|
||||
* @return array{get:string,add:string,del:string}|WP_Error
|
||||
*/
|
||||
private static function meta_store($parent_id, $parent_type = 'post') {
|
||||
if ($parent_type === 'comment') {
|
||||
return [
|
||||
'get' => 'get_comment_meta',
|
||||
'add' => 'add_comment_meta',
|
||||
'del' => 'delete_comment_meta',
|
||||
];
|
||||
}
|
||||
if ($parent_type === 'post') {
|
||||
return [
|
||||
'get' => 'get_post_meta',
|
||||
'add' => 'add_post_meta',
|
||||
'del' => 'delete_post_meta',
|
||||
];
|
||||
}
|
||||
return new WP_Error('invalid_parent', 'parent_type must be post or comment.');
|
||||
}
|
||||
|
||||
/** Image upload wrapper that works for posts or comments. */
|
||||
public static function handle_upload_for_parent($parent_id, $file, $parent_type = 'post') {
|
||||
$store = self::meta_store($parent_id, $parent_type);
|
||||
if (is_wp_error($store)) return $store;
|
||||
|
||||
if (!is_array($file) || $file['error'] !== UPLOAD_ERR_OK) {
|
||||
return new WP_Error('upload_error', 'Upload failed.');
|
||||
}
|
||||
if ($file['size'] > self::$max_file_size) {
|
||||
return new WP_Error('file_too_large', 'File exceeds 10 MB limit.');
|
||||
}
|
||||
$mime = mime_content_type($file['tmp_name']);
|
||||
if (!in_array($mime, self::$image_types, true)) {
|
||||
return new WP_Error('invalid_type', 'Only JPEG, PNG, GIF, and WebP are allowed.');
|
||||
}
|
||||
|
||||
$existing = call_user_func($store['get'], $parent_id, self::META_KEY_IMAGES, false);
|
||||
$existing = array_filter(array_map('intval', (array) $existing));
|
||||
if (count($existing) >= self::$max_images) {
|
||||
return new WP_Error('too_many', 'Maximum ' . self::$max_images . ' images per beep.');
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/image.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
|
||||
$file_return = wp_handle_sideload($file, [
|
||||
'test_form' => false,
|
||||
'mimes' => [
|
||||
'jpg|jpeg' => 'image/jpeg',
|
||||
'png' => 'image/png',
|
||||
'gif' => 'image/gif',
|
||||
'webp' => 'image/webp',
|
||||
],
|
||||
]);
|
||||
|
||||
if (isset($file_return['error'])) {
|
||||
return new WP_Error('sideload_error', $file_return['error']);
|
||||
}
|
||||
|
||||
$attachment = [
|
||||
'post_mime_type' => $file_return['type'],
|
||||
'post_title' => preg_replace('/\.[^.]+$/', '', basename($file_return['file'])),
|
||||
'post_content' => '',
|
||||
'post_status' => 'inherit',
|
||||
'guid' => $file_return['url'],
|
||||
];
|
||||
|
||||
// Attachments still need a post parent for WP core; use the comment's post ID when on a comment.
|
||||
$attach_parent = $parent_type === 'comment'
|
||||
? (int) get_comment($parent_id)->comment_post_ID
|
||||
: $parent_id;
|
||||
$attachment_id = wp_insert_attachment($attachment, $file_return['file'], $attach_parent);
|
||||
if (is_wp_error($attachment_id)) {
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
$attach_data = wp_generate_attachment_metadata($attachment_id, $file_return['file']);
|
||||
wp_update_attachment_metadata($attachment_id, $attach_data);
|
||||
|
||||
call_user_func($store['add'], $parent_id, self::META_KEY_IMAGES, $attachment_id);
|
||||
|
||||
return [
|
||||
'id' => $attachment_id,
|
||||
'url' => wp_get_attachment_url($attachment_id),
|
||||
'thumb' => self::get_image_url($attachment_id, 'thumbnail'),
|
||||
'sizes' => self::get_image_sizes($attachment_id),
|
||||
];
|
||||
}
|
||||
|
||||
/** Image removal wrapper. */
|
||||
public static function remove_image_from_parent($parent_id, $attachment_id, $parent_type = 'post') {
|
||||
$store = self::meta_store($parent_id, $parent_type);
|
||||
if (is_wp_error($store)) return $store;
|
||||
$ids = call_user_func($store['get'], $parent_id, self::META_KEY_IMAGES, false);
|
||||
$ids = array_values(array_filter((array) $ids, fn($id) => (int) $id !== (int) $attachment_id));
|
||||
call_user_func($store['del'], $parent_id, self::META_KEY_IMAGES);
|
||||
foreach ($ids as $id) {
|
||||
call_user_func($store['add'], $parent_id, self::META_KEY_IMAGES, $id);
|
||||
}
|
||||
wp_delete_attachment($attachment_id, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Voice upload wrapper. */
|
||||
public static function handle_voice_upload_for_parent($parent_id, $file, $parent_type = 'post') {
|
||||
$store = self::meta_store($parent_id, $parent_type);
|
||||
if (is_wp_error($store)) return $store;
|
||||
|
||||
if (!is_array($file) || $file['error'] !== UPLOAD_ERR_OK) {
|
||||
return new WP_Error('upload_error', 'Upload failed.');
|
||||
}
|
||||
if ($file['size'] > self::$max_audio_size) {
|
||||
return new WP_Error('file_too_large', 'Voice note exceeds 20 MB limit.');
|
||||
}
|
||||
$mime = mime_content_type($file['tmp_name']);
|
||||
if (!in_array($mime, self::$audio_types, true)) {
|
||||
return new WP_Error('invalid_type', 'Only MP3, OGG, WAV, WebM, and M4A audio are allowed.');
|
||||
}
|
||||
|
||||
require_once ABSPATH . 'wp-admin/includes/file.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/media.php';
|
||||
|
||||
$file_return = wp_handle_upload($file, [
|
||||
'test_form' => false,
|
||||
'mimes' => [
|
||||
'mp3' => 'audio/mpeg',
|
||||
'ogg' => 'audio/ogg',
|
||||
'wav' => 'audio/wav',
|
||||
'webm' => 'audio/webm',
|
||||
'm4a' => 'audio/mp4',
|
||||
],
|
||||
]);
|
||||
|
||||
if (isset($file_return['error'])) {
|
||||
return new WP_Error('upload_error', $file_return['error']);
|
||||
}
|
||||
|
||||
$attachment = [
|
||||
'post_mime_type' => $file_return['type'],
|
||||
'post_title' => preg_replace('/\.[^.]+$/', '', basename($file_return['file'])),
|
||||
'post_content' => '',
|
||||
'post_status' => 'inherit',
|
||||
'guid' => $file_return['url'],
|
||||
];
|
||||
|
||||
$attach_parent = $parent_type === 'comment'
|
||||
? (int) get_comment($parent_id)->comment_post_ID
|
||||
: $parent_id;
|
||||
$attachment_id = wp_insert_attachment($attachment, $file_return['file'], $attach_parent);
|
||||
if (is_wp_error($attachment_id)) {
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
$attach_data = wp_generate_attachment_metadata($attachment_id, $file_return['file']);
|
||||
wp_update_attachment_metadata($attachment_id, $attach_data);
|
||||
|
||||
$url = wp_get_attachment_url($attachment_id);
|
||||
call_user_func($store['add'], $parent_id, 'beep_reply_voice_url', $url);
|
||||
call_user_func($store['add'], $parent_id, 'beep_reply_voice_id', $attachment_id);
|
||||
|
||||
return ['id' => $attachment_id, 'url' => $url];
|
||||
}
|
||||
|
||||
public static function handle_voice_upload($post_id, $file) {
|
||||
if (!is_array($file) || $file['error'] !== UPLOAD_ERR_OK) {
|
||||
@@ -312,9 +490,6 @@ class Beep_Media {
|
||||
}
|
||||
|
||||
// Video file upload support
|
||||
private static $video_types = ['video/mp4', 'video/webm', 'video/ogg', 'video/quicktime'];
|
||||
private static $max_video_size = 100 * 1024 * 1024; // 100 MB
|
||||
|
||||
public static function handle_video_upload($post_id, $file) {
|
||||
if (!is_array($file) || $file['error'] !== UPLOAD_ERR_OK) {
|
||||
return new WP_Error('upload_error', 'Upload failed.');
|
||||
|
||||
Reference in New Issue
Block a user