PHP Functions Reference
To be able to implement this guide, you need to learn how to insert PHP snippets to your website.
You can find guide here: WP Beginner
This page lists all public PHP functions available in the Better Messages plugin. Use these to programmatically manage conversations, messages, participants, and more.
Sending Messages#
new_message#
Sends a new reply to an existing conversation or creates a new conversation with a first message.
Starting a new conversation:
$sender_id = get_current_user_id();
$recipients = [2, 3, 4];
$content = 'new conversation message content';
$subject = 'Subject';
$thread_id = Better_Messages()->functions->new_message([
'sender_id' => $sender_id,
'content' => $content,
'subject' => $subject,
'recipients' => $recipients,
'return' => 'thread_id',
'error_type' => 'wp_error'
]);
if ( is_wp_error( $thread_id ) ) {
$error = $thread_id->get_error_message();
// Process error
} else {
// Thread created
}
Replying to an existing conversation:
$sender_id = get_current_user_id();
$thread_id = 6620;
$content = 'new message content';
$message_id = Better_Messages()->functions->new_message([
'sender_id' => $sender_id,
'thread_id' => $thread_id,
'content' => $content,
'return' => 'message_id',
'error_type' => 'wp_error'
]);
if ( is_wp_error( $message_id ) ) {
$error = $message_id->get_error_message();
// Process error
} else {
// Message created
}
Pre-moderation: new_message() applies the site's Pre-Moderation settings to the sender, the same way the messenger does. A message from a sender who must be moderated is saved as pending and waits for approval in the Administration page. Two arguments change this:
'skip_moderation' => truesends the message straight away. Use it for automatic messages that pre-moderation should never hold, such as a notice your plugin sends in the member's name. A message sent this way does not count as the sender's approved message under First-Time Senders.'is_pending' => 0or1sets the state yourself. Pre-moderation is not checked, and the value is kept as given.
Better_Messages()->functions->new_message([
'sender_id' => $sender_id,
'thread_id' => $thread_id,
'content' => 'Your order has shipped',
'skip_moderation' => true,
]);
Creating Conversations#
create_new_conversation#
Creates a new empty conversation programmatically and returns the conversation ID.
Parameters:
$user_ids(array) — Array of user IDs to include$subject(string) — Conversation subject
Returns: int|false — Thread ID on success, false on failure
$user_ids = [1, 2, 3];
$subject = 'Conversation Subject';
$thread_id = Better_Messages()->functions->create_new_conversation( $user_ids, $subject );
get_private_conversation_id#
Gets an existing private conversation with a user, or creates one if it doesn't exist.
Parameters:
$to(int) — Recipient user ID$from(int|null) — Sender/initiator user ID. Defaultnull(current user)$create(bool) — Whether to create if not found. Defaulttrue$subject(string) — Subject for new conversations. Default''$uniqueKey(string|null) — Optional unique key for context-specific conversations. Defaultnull
Returns: array — Result with result key ('thread_found', 'thread_created', or 'not_allowed') and thread_id or errors
$to = 3;
$from = get_current_user_id();
$create = true;
$subject = 'New conversation subject';
$result = Better_Messages()->functions->get_private_conversation_id( $to, $from, $create, $subject );
switch( $result['result'] ){
case 'thread_created':
case 'thread_found':
$thread_id = $result['thread_id'];
// Do something with thread ID
break;
case 'not_allowed':
$errors = $result['errors'];
foreach( $errors as $error ){
// echo $error;
}
break;
}
get_unique_conversation_id#
Gets or creates a unique conversation based on a set of user IDs and a unique key. Useful for creating unique conversations between buyers and sellers for different products.
If a conversation with the unique key was already created for the given users, returns the existing thread ID — otherwise creates a new one.
Parameters:
$user_ids(array) — Array of user IDs$unique_key(string) — Unique identifier (e.g.,'product_123')$subject(string) — Subject (only used when creating new conversation)
Returns: int|false — Thread ID on success, false on failure
$user_ids = [1, 2];
$unique_key = 'product_123';
$subject = 'Questions about your Product 123';
$thread_id = Better_Messages()->functions->get_unique_conversation_id( $user_ids, $unique_key, $subject );
Participants#
add_participant_to_thread#
Adds a user to an existing conversation.
Parameters:
$thread_id(int) — Conversation ID$user_id(int) — User ID to add$context(string) — Optional, passed on tobetter_messages_can_add_participantandbetter_messages_participant_added
Returns: bool — true if added, false if not, which includes someone already in the conversation and a refusal by better_messages_can_add_participant
$user_id = 3;
$thread_id = 6610;
$user_added = Better_Messages()->functions->add_participant_to_thread( $thread_id, $user_id );
remove_participant_from_thread#
Removes a user from an existing conversation.
Parameters:
$thread_id(int) — Conversation ID$user_id(int) — User ID to remove
Returns: bool — true if removed, false if not
$user_id = 3;
$thread_id = 6610;
$user_removed = Better_Messages()->functions->remove_participant_from_thread( $thread_id, $user_id );
is_user_participant#
Checks if a user is a participant of a conversation.
Parameters:
$thread_id(int) — Conversation ID$user_id(int) — User ID to check
Returns: bool — true if participant, false if not
$user_id = 3;
$thread_id = 6610;
$is_participant = Better_Messages()->functions->is_user_participant( $thread_id, $user_id );
get_recipients_ids#
Retrieves all user IDs participating in a conversation.
Parameters:
$thread_id(int) — Conversation ID
Returns: array — Array of user IDs, empty array if no participants or thread doesn't exist
$user_ids = Better_Messages()->functions->get_recipients_ids( $thread_id );
Thread Management#
archive_thread#
Archives (hides) a conversation for a specific user. Equivalent to the user deleting the conversation — it only hides it from their list, not actually deleted from the database.
Parameters:
$user_id(int) — User ID$thread_id(int) — Conversation ID
$user_id = 3;
$thread_id = 6610;
Better_Messages()->functions->archive_thread( $user_id, $thread_id );
set_user_unread_count_for_thread#
Sets the unread message count for a specific user in a specific conversation.
Parameters:
$user_id(int) — User ID$thread_id(int) — Conversation ID$unread_count(int) — Number of unread messages
$user_id = 3;
$thread_id = 3;
$unread_count = 1;
Better_Messages()->functions->set_user_unread_count_for_thread( $user_id, $thread_id, $unread_count );
Thread Meta#
get_thread_meta#
Gets thread metadata for a specific key. Works like WordPress get_post_meta() — returns the stored value for the given key, or empty string if not found.
Parameters:
$thread_id(int) — Conversation ID$key(string) — Meta key
Returns: mixed — Meta value
$thread_id = 1;
$key = 'custom_data';
$custom_data = Better_Messages()->functions->get_thread_meta( $thread_id, $key );
update_thread_meta#
Updates thread metadata for a specific key. Creates the entry if it doesn't exist, similar to WordPress update_post_meta(). Overwrites any existing value for the key.
Parameters:
$thread_id(int) — Conversation ID$key(string) — Meta key$value(mixed) — Meta value
$thread_id = 1;
$key = 'custom_key';
Better_Messages()->functions->update_thread_meta( $thread_id, $key, 'custom_data' );
delete_thread_meta#
Deletes thread metadata for a specific key. Removes the meta entry entirely from the database, similar to WordPress delete_post_meta().
Parameters:
$thread_id(int) — Conversation ID$key(string) — Meta key
$thread_id = 1;
$key = 'custom_key';
Better_Messages()->functions->delete_thread_meta( $thread_id, $key );
URLs & Links#
create_conversation_link#
Generates a URL that points to a new conversation screen or directly to a conversation.
Parameters:
$user_id(int) — Recipient user ID$subject(string) — Predefined subject (leave empty to not prefill)$message(string) — Predefined message content (leave empty to not prefill)$fastStart(bool) — Iftrue, opens the conversation directly instead of showing the new conversation screen$scrollToContainer(bool) — Automatically scroll to messages container on page load
Returns: string — URL
New conversation screen:
$user_id = 3;
$subject = 'Conversation Subject';
$message = 'Conversation Predefined Content';
$fastStart = false;
$scrollToContainer = true;
$url = Better_Messages()->functions->create_conversation_link( $user_id, $subject, $message, $fastStart, $scrollToContainer );
echo '<a href="' . $url . '">Private Message</a>';
Opening conversation directly:
$user_id = 3;
$fastStart = true;
$scrollToContainer = true;
$url = Better_Messages()->functions->create_conversation_link( $user_id, '', '', $fastStart, $scrollToContainer );
echo '<a href="' . $url . '">Fast Private Message</a>';
get_user_messages_url#
Generates a URL pointing to a user's personal inbox, optionally with a specific conversation opened.
Parameters:
$user_id(int) — User ID for whom the link is generated$thread_id(int, optional) — Specific conversation to open
Returns: string — URL
Specific conversation:
$user_id = 3;
$thread_id = 111;
$url = Better_Messages()->functions->get_user_messages_url( $user_id, $thread_id );
General inbox:
$user_id = 3;
$url = Better_Messages()->functions->get_user_messages_url( $user_id );
Layout Rendering#
get_conversation_layout#
Outputs a single conversation layout for embedding.
Parameters:
$thread_id(int) — Conversation ID to display
Returns: string — HTML
$thread_id = 123;
echo Better_Messages()->functions->get_conversation_layout( $thread_id );
get_conversations_layout#
Displays an interactive conversations list anywhere on your website.
Parameters:
$height(int) — Height of the list in pixels
Returns: string — HTML
$height = 400;
echo Better_Messages()->functions->get_conversations_layout( $height );

Messages#
get_message#
Fetches a single message by ID from the database. Returns the complete message row object including sender_id, thread_id, message content, timestamps, and subject. Returns null if the message doesn't exist.
Parameters:
$message_id(int) — Message ID
Returns: object|null
$message = Better_Messages()->functions->get_message( $message_id );
if ( $message ) {
$sender = $message->sender_id;
$content = $message->message;
$thread = $message->thread_id;
}
get_messages#
Fetches messages from a thread with various filtering options.
Parameters:
$thread_id(int) — Thread ID$message(int|false) — Optional message ID for context. Defaultfalse$action(string) — Retrieval mode:'last_messages','from_message','to_message'. Default'last_messages'$count(int) — Number of messages to retrieve. Default50
Returns: array — Array of message objects
// Get last 20 messages from a thread
$messages = Better_Messages()->functions->get_messages( $thread_id, false, 'last_messages', 20 );
send_system_message#
Sends a system message (non-user, sender_id = 0) with metadata. Useful for events, notifications, or automated messages within a thread.
Parameters:
$thread_id(int) — Thread ID$type(string) — System message type identifier$data(array) — Additional metadata. Default[]
Returns: int — Message ID
Better_Messages()->functions->send_system_message( $thread_id, 'user_joined', [
'user_id' => $user_id,
'user_name' => $user_name,
] );
delete_message#
Deletes a message and its associated attachments. Triggers better_messages_before_message_delete action.
Parameters:
$message_id(int) — Message ID to delete$thread_id(int|false) — Thread ID. Defaultfalse(auto-detected)$update_thread(bool) — Whether to update thread timestamps. Defaulttrue$deleteMethod(string|null) —'delete'(hard) or'softdelete'. Defaultnull(uses plugin setting)
Better_Messages()->functions->delete_message( $message_id );
update_message#
Updates an existing message with new content.
Parameters (as array):
sender_id(int) — User performing the updatemessage_id(int) — Message ID to updatecontent(string) — New message contentthread_id(int) — Thread ID
Better_Messages()->functions->update_message([
'sender_id' => get_current_user_id(),
'message_id' => $message_id,
'thread_id' => $thread_id,
'content' => 'Updated message content',
]);
Message Meta#
add_message_meta#
Adds metadata to a message.
Parameters:
$message_id(int) — Message ID$meta_key(string) — Meta key$meta_value(mixed) — Meta value$unique(bool) — Prevent duplicate keys. Defaulttrue
Better_Messages()->functions->add_message_meta( $message_id, 'priority', 'high' );
get_message_meta#
Gets message metadata for a specific key. Wrapper around WordPress get_metadata(). Returns the stored value by default, or an array of all values if $single is false.
Parameters:
$message_id(int) — Message ID$key(string) — Meta key. Default''(all meta)$single(bool) — Return single value. Defaulttrue
Returns: mixed
$priority = Better_Messages()->functions->get_message_meta( $message_id, 'priority' );
update_message_meta#
Updates message metadata for a specific key. Wrapper around WordPress update_metadata(). Creates the entry if it doesn't exist, overwrites if it does.
Parameters:
$message_id(int) — Message ID$meta_key(string) — Meta key$meta_value(mixed) — New value
Better_Messages()->functions->update_message_meta( $message_id, 'priority', 'low' );
delete_message_meta#
Deletes message metadata for a specific key. Wrapper around WordPress delete_metadata(). If $meta_value is provided, only deletes entries matching that specific value.
Parameters:
$message_id(int) — Message ID$meta_key(string) — Meta key$meta_value(mixed, optional) — Specific value to delete
Better_Messages()->functions->delete_message_meta( $message_id, 'priority' );
Thread Information#
get_thread#
Fetches a thread object by ID with WordPress object cache support. The result includes the thread's subject, type, and associated metadata. Returns false if the thread doesn't exist.
Parameters:
$thread_id(int) — Thread ID
Returns: object|false
$thread = Better_Messages()->functions->get_thread( $thread_id );
if ( $thread ) {
$subject = $thread->subject;
}
get_thread_type#
Gets the type of a thread. Returns 'thread' for private conversations, 'group' for group-linked conversations, or other types for chat rooms. The result is cached and validated against active group plugins.
Parameters:
$thread_id(int) — Thread ID
Returns: string — 'thread' (private), 'group', or chat room type
$type = Better_Messages()->functions->get_thread_type( $thread_id );
if ( $type === 'group' ) {
// Handle group conversation
}
change_thread_subject#
Changes a thread's subject in the database and triggers better_messages_thread_updated and better_messages_info_changed actions. All thread participants receive a real-time update notification so the UI reflects the new subject immediately.
Parameters:
$thread_id(int) — Thread ID$new_subject(string) — New subject text
Returns: string — The escaped subject that was set
Better_Messages()->functions->change_thread_subject( $thread_id, 'New Subject' );
find_existing_threads#
Finds all existing private threads between two users. Excludes deleted threads and threads with disabled replies. Useful for checking if a PM conversation already exists before creating a new one.
Parameters:
$from(int) — First user ID$to(int) — Second user ID$exclude_deleted(bool|null) — Whether to exclude deleted threads
Returns: array — Array of thread IDs
$threads = Better_Messages()->functions->find_existing_threads( $user_id_1, $user_id_2 );
clear_thread#
Deletes all messages in a thread, its mentions included, and resets unread counters, read timestamps, and delivered timestamps for all participants. The conversation itself and its participants stay. This is a destructive operation — all message content and attachments are permanently removed. Fires better_messages_thread_cleared.
Parameters:
$thread_id(int) — Thread ID
Better_Messages()->functions->clear_thread( $thread_id );
erase_thread#
Deletes a whole conversation for good: all its messages with their attachments, its metadata, and its participant records, so it disappears for everyone. Use it to remove conversations from code, for example when a member's access ends. Fires better_messages_thread_erased. clear_thread empties a conversation and keeps it.
Parameters:
$thread_id(int) — Thread ID
Better_Messages()->functions->erase_thread( $thread_id );
Delete the private conversations between two users, as find_existing_threads finds them:
foreach ( Better_Messages()->functions->find_existing_threads( $user_id_1, $user_id_2 ) as $thread_id ) {
Better_Messages()->functions->erase_thread( $thread_id );
}
Unread Counts#
get_user_unread_count#
Gets the total unread message count across all non-deleted threads for a user. Sums the unread_count values above 0 from the recipients table, so a conversation the user marked as unread (-1) is not counted. Useful for displaying a global unread badge.
Parameters:
$user_id(int) — User ID
Returns: int
$total_unread = Better_Messages()->functions->get_user_unread_count( $user_id );
get_user_unread_for_thread#
Gets the unread count for a specific user in a specific thread from the recipients table. Returns 0 if the user has read all messages or if the record doesn't exist, and -1 for a conversation the user marked as unread.
Parameters:
$user_id(int) — User ID$thread_id(int) — Thread ID
Returns: int
$unread = Better_Messages()->functions->get_user_unread_for_thread( $user_id, $thread_id );
messages_mark_thread_read#
Marks all messages in a thread as read for a user by resetting unread_count to 0 and updating last_read and last_delivered timestamps. Clears related caches. Defaults to the current user if $user_id is not provided.
Parameters:
$thread_id(int) — Thread ID$user_id(int|false) — User ID. Defaultfalse(current user)
Better_Messages()->functions->messages_mark_thread_read( $thread_id, $user_id );
mark_thread_unread#
Marks a conversation as unread again for a user (Better Messages 3.2, Mark as unread). Sets unread_count to -1, which shows a dot in the conversations list and counts in no unread total, passes the mark to the realtime server on the WebSocket version so it reaches the other devices of the user, and fires better_messages_thread_marked_unread. Opening the conversation or a new message in it ends the mark.
Refuses (returns false) when Settings → Messaging → Conversation Features → Mark as Unread is off, in a presence-based chat room, and for a user who is not a participant. With $only_read, it also leaves a conversation the site counts unread as it is and returns false for it.
Parameters:
$thread_id(int) — Thread ID$user_id(int) — User ID, negative for a guest$only_read(bool) — Mark only a conversation the site counts read. Defaultfalse
Returns: bool — true once the conversation is marked
Better_Messages()->functions->mark_thread_unread( $thread_id, $user_id );
get_user_muted_threads#
Gets all threads muted by a user from the recipients table. Returns an empty array if the muting feature is disabled in settings or if the user has no muted threads.
Parameters:
$user_id(int) — User ID
Returns: array — Array of muted thread IDs, empty array if none
$muted = Better_Messages()->functions->get_user_muted_threads( $user_id );
Permissions#
can_reply_in_conversation#
Checks if a user can reply in a conversation, with detailed error messages.
Parameters:
$user_id(int) — User ID$thread_id(int) — Thread ID
Returns: array — ['result' => 'allowed'] or ['result' => 'not_allowed', 'errors' => [...]]
$check = Better_Messages()->functions->can_reply_in_conversation( $user_id, $thread_id );
if ( $check['result'] === 'allowed' ) {
// User can reply
} else {
// $check['errors'] contains error messages
}
can_start_conversation#
Validates if a user can create a new conversation with specific recipients.
Parameters:
$starter_id(int) — User starting the conversation$recipients(array) — Recipient user IDs. Default[]$uniqueKey(string|null) — Optional unique key. Defaultnull
Returns: array — Result with 'result' key
$check = Better_Messages()->functions->can_start_conversation( $user_id, [3, 4, 5] );
if ( $check['result'] === 'allowed' ) {
// User can start conversation
}
Moderators#
get_moderators#
Gets all moderator user IDs for a thread from the thread's moderators metadata. Returns an empty array if no moderators are assigned. Moderators have additional permissions like muting, banning, and deleting messages from other users.
Parameters:
$thread_id(int) — Thread ID
Returns: array — Array of moderator user IDs
$moderators = Better_Messages()->functions->get_moderators( $thread_id );
add_moderator#
Adds a user as moderator to a thread by updating the thread's moderators metadata. Skips if the user is already a moderator. Triggers better_messages_info_changed action so all participants see the updated moderator list.
Parameters:
$thread_id(int) — Thread ID$user_id(int) — User ID to promote
Better_Messages()->functions->add_moderator( $thread_id, $user_id );
remove_moderator#
Removes a user from the moderator list of a thread by updating the thread's moderators metadata. Triggers better_messages_info_changed action if the user was actually a moderator. The user remains a regular participant.
Parameters:
$thread_id(int) — Thread ID$user_id(int) — User ID to demote
Better_Messages()->functions->remove_moderator( $thread_id, $user_id );
User Information#
get_name#
Gets a user's display name by checking fullname first, then falling back to display_name. Returns "Deleted User" if the user doesn't exist. The result passes through the bp_better_messages_display_name filter, allowing customization by other plugins.
Parameters:
$user_id(int) — User ID (can be negative for guests)
Returns: string
$name = Better_Messages()->functions->get_name( $user_id );
Chat Rooms#
get_chat_thread_id#
Gets the messaging thread ID associated with a chat room post. Looks up the thread ID from post metadata. Returns false if the chat room has no associated thread or if the metadata is invalid.
Parameters:
$chat_id(int) — Chat room post ID
Returns: int|false — Thread ID or false if not found
$thread_id = Better_Messages()->chats->get_chat_thread_id( $chat_id );
get_chat_settings#
Gets all settings for a chat room (permissions, notifications, display options), merged with defaults.
Parameters:
$chat_id(int) — Chat room post ID
Returns: array — Complete settings array
$settings = Better_Messages()->chats->get_chat_settings( $chat_id );
$can_join_roles = $settings['can_join']; // Array of roles that can join
Group Calls#
get_group_call_participants#
This functionality is available only with the WebSocket version.
Returns how many people are currently in a conversation's group call. Group video and group audio are separate rooms, so ask for each type you care about — one conversation can have people in both at the same time.
Use this for server-side decisions, above all the capacity gate below. Each uncached call reaches out to the call server, so it is the wrong tool for a page that displays a live number — that belongs in the browser, where BetterMessages.getGroupCallParticipants() answers over the WebSocket without touching WordPress at all.
Returns 0 when no call is running, when the conversation does not exist, or when the site has no WebSocket license.
Parameters:
$thread_id(int) — Conversation ID$type(string) —'video'(default) or'audio'
Returns: int — People currently in that call
$thread_id = 1;
$in_video = Better_Messages()->functions->get_group_call_participants( $thread_id, 'video' );
$in_audio = Better_Messages()->functions->get_group_call_participants( $thread_id, 'audio' );
There is no event for a participant leaving a call on the server, because a member closes the call in their browser without WordPress being involved. In the browser you do get one — better_messages_group_call_status fires whenever a count changes, in either direction.
To cap a room and send people elsewhere once it fills up, pair this with better_messages_group_call_join_custom_error. The filter runs before the person is connected, so nobody slips in between two reads:
add_filter( 'better_messages_group_call_join_custom_error', 'send_to_overflow_room', 10, 4 );
function send_to_overflow_room( $error, $thread_id, $user_id, $type ){
if( ! empty( $error ) ){
return $error;
}
if( Better_Messages()->functions->get_group_call_participants( $thread_id, $type ) >= 20 ){
return __( 'This room is full. Please join the overflow room.', 'your-textdomain' );
}
return $error;
}
Group calls have no fixed size: a site includes 32 people at once across all its group calls, and more join with WordPlus Cloud credits. A threshold like this one keeps a room at the size you choose.
Results are cached briefly so a burst of joins does not mean a burst of outbound requests, and the window is filterable with better_messages_group_call_participants_cache_time.
Realtime Events#
send_realtime_event#
This functionality is available only with the WebSocket version.
Sends a custom realtime event directly to user browsers using WebSocket servers. To receive events on the frontend, use the better_messages_realtime_event JavaScript hook.
Parameters:
$user_ids(array) — User IDs to send events to$data(mixed) — Event data (string, array, or object)
// Check if WebSocket class exists to avoid fatal errors
if( class_exists('Better_Messages_WebSocket') ){
// Send simple string
Better_Messages_WebSocket()->send_realtime_event( [1,2,3], 'custom string' );
// Send more complex data sets
Better_Messages_WebSocket()->send_realtime_event( [1,2,3], [
'custom data' => 'test'
] );
}