Changeset 3771693 for joinotify/trunk/admin/src/Core/Functions.php
- Timestamp:
- 10/28/2026 09:22:17 PM (7 days ago)
- File:
-
- 1 edited
-
joinotify/trunk/admin/src/Core/Functions.php (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
joinotify/trunk/admin/src/Core/Functions.php
r3722220 r3771693 8 8 9 9 use MeuMouse\Joinotify\Api\Transport; 10 use MeuMouse\Joinotify\Api\Contact_Window; 11 use MeuMouse\Joinotify\Api\Template_Repository; 10 12 use MeuMouse\Joinotify\Api\Extensions; 11 13 use MeuMouse\Joinotify\Admin\Admin; … … 16 18 use MeuMouse\Joinotify\Core\Message_History; 17 19 use MeuMouse\Joinotify\Core\Logger; 20 use MeuMouse\Joinotify\Core\Workflow_Processor; 18 21 use MeuMouse\Joinotify\Notifications\Channel_Manager; 19 22 use MeuMouse\Joinotify\Notifications\Notification_Message; … … 80 83 81 84 return $response; 85 } 86 87 88 /** 89 * Send an approved WhatsApp template and say what happened. 90 * 91 * Meant for integrations that need the outcome right away — a login code, a 92 * transactional notice sent from another plugin. The send goes through the 93 * same path as the workflow actions (sender check, one-line parameters, message 94 * history, debug log), but in a single attempt by default: a code that expires 95 * in minutes is worse than useless when a retry delivers it an hour later. 96 * 97 * `$args`: 98 * - `sender` — origin number in digits; defaults to the first connected sender. 99 * - `queue_on_failure` — put a send refused for a transient reason (rate limit, 100 * API unavailable) in the retry queue; default false. 101 * - `context` — dispatch context for the message history while this send runs, 102 * e.g. `array( 'source' => 'otp' )`, which masks the template values (login 103 * codes) before they are stored. The context set before the call is restored. 104 * 105 * @since 2.6.0 106 * @param string $receiver | Recipient phone, with or without the country code. 107 * @param string $template_name | Approved template name. 108 * @param string $language | Template language code (e.g. pt_BR). 109 * @param array $components | Meta components with the parameters already resolved. 110 * @param array $args | Options: sender, queue_on_failure, context. 111 * @return array{message_id:string,status:string}|WP_Error `status` is `sent`, or `queued` 112 * (with an empty `message_id`) when `queue_on_failure` put it in the retry queue. The 113 * error data carries `status` (HTTP status to answer with), `response_code` (the 114 * Joinotify API's, 0 when not reached), `reason`, `detail`, `meta_code`, `retryable` 115 * and, for a 429, `retry_after` in seconds. 116 */ 117 function joinotify_send_whatsapp_template( string $receiver, string $template_name, string $language = 'pt_BR', array $components = array(), array $args = array() ) { 118 $args = wp_parse_args( $args, array( 119 'sender' => '', 120 'queue_on_failure' => false, 121 'context' => array(), 122 ) ); 123 124 $sender = is_scalar( $args['sender'] ) ? preg_replace( '/\D/', '', (string) $args['sender'] ) : ''; 125 126 if ( '' === $sender ) { 127 $sender = preg_replace( '/\D/', '', (string) joinotify_get_first_sender() ); 128 } 129 130 if ( '' === $sender ) { 131 return new WP_Error( 'joinotify_no_sender', __( 'No WhatsApp number is connected to Joinotify to send from.', 'joinotify' ), array( 132 'status' => 503, 133 'response_code' => 0, 134 'reason' => 'no_sender', 135 'detail' => '', 136 'meta_code' => 0, 137 'retryable' => false, 138 ) ); 139 } 140 141 $context = is_array( $args['context'] ) ? $args['context'] : array(); 142 $previous_context = Message_History::get_context(); 143 144 if ( ! empty( $context ) ) { 145 Message_History::set_context( $context ); 146 } 147 148 try { 149 $details = Transport::send_message_template( $sender, $receiver, $template_name, $language, $components, 0, (bool) $args['queue_on_failure'], true ); 150 } finally { 151 if ( ! empty( $context ) ) { 152 Message_History::set_context( $previous_context ); 153 } 154 } 155 156 return Transport::template_send_result( $details ); 157 } 158 159 160 /** 161 * List the WhatsApp message templates of the connected account. 162 * 163 * Served from a 15-minute local cache of the platform's own mirror; `force` 164 * asks the platform to read Meta again. Every template says what it expects: 165 * `header_format` (`TEXT`, `IMAGE`, `VIDEO`, `DOCUMENT`, `LOCATION` or empty), 166 * `buttons` and `variables`, one entry per value in the order Meta wants them 167 * (`component`, `sub_type`, `index`, `key`, `label`, `format` and, for a URL 168 * button, the button's `url` with its token). A value with no token has an 169 * empty `key`: a media header (`format` `image`, `video`, `document`), a 170 * copy-code button (`sub_type` `copy_code`) or the login-code button of an 171 * AUTHENTICATION template (`format` `otp`). A location header is four 172 * variables (`format` `location`), an expiring offer one `limited_time_offer` 173 * variable, and the variables of a carousel card carry its position in `card` 174 * (-1 outside a carousel), as `cards` describes each card. 175 * 176 * @since 2.6.0 177 * @param array $args | Optional `status`, `waba_id` and `force`. 178 * @return array|WP_Error `templates`, `total`, `waba_id`, `synced_at`, `stale`, `sync_error`. 179 */ 180 function joinotify_get_whatsapp_templates( array $args = array() ) { 181 return Template_Repository::get_templates( $args ); 182 } 183 184 185 /** 186 * Find one WhatsApp message template by name. 187 * 188 * Reads the local copy first and loads the listing once when nothing local 189 * knows the template, so it is safe on a send path. 190 * 191 * @since 2.6.0 192 * @param string $name | Template name as approved on Meta. 193 * @param string $language | Language to prefer (e.g. pt_BR); empty for any. 194 * @return array|null Normalized template (as in joinotify_get_whatsapp_templates()), or null. 195 */ 196 function joinotify_get_whatsapp_template( string $name, string $language = '' ) { 197 return Template_Repository::find_or_fetch( $name, $language ); 198 } 199 200 201 /** 202 * Pack template values already resolved into the `components` of a template send. 203 * 204 * Each variable is an entry of the template's `variables` with its `value` 205 * set; a media header is a `header` entry with `format` (`image`, `video`, 206 * `document`) and the file link (or a Meta media id) as its value, and a 207 * `copy_code` button entry takes the coupon. Location, offer expiration and 208 * carousel card entries are packed as their template lists them (see 209 * joinotify_get_whatsapp_templates()). Values are not run through the 210 * Joinotify placeholders: they go out as given, brought to the one line Meta 211 * accepts, and named variables carry their `parameter_name`. 212 * 213 * @since 2.6.0 214 * @param array $variables | Variables with their resolved `value`. 215 * @return array Components for joinotify_send_whatsapp_template(). 216 */ 217 function joinotify_build_whatsapp_template_components( array $variables ) { 218 return Workflow_Processor::components_from_values( $variables ); 219 } 220 221 222 /** 223 * Write the text a recipient reads for a template and its components. 224 * 225 * Header, body and footer with the values in place; a template the site does 226 * not know is described by its name and values instead. 227 * 228 * @since 2.6.0 229 * @param string $name | Template name. 230 * @param string $language | Template language code. 231 * @param array $components | Components as sent. 232 * @return string 233 */ 234 function joinotify_render_whatsapp_template( string $name, string $language = '', array $components = array() ) { 235 $rendered = Template_Repository::render( $name, $language, $components ); 236 237 return (string) ( $rendered['text'] ?? '' ); 238 } 239 240 241 /** 242 * Read the customer service window of a contact on one of the account numbers. 243 * 244 * Free text and media reach a contact only while the window opened by the 245 * contact's last message is open (24 hours, 72 hours after a click-to-WhatsApp 246 * ad); outside it only an approved template goes out. The platform answers for 247 * the window, webhooks or not. `unknown` means it could not be asked — not 248 * connected, unreachable, rate limited — so a caller that sends a template on 249 * anything but `open` is always right. 250 * 251 * @since 2.6.0 252 * @param string $phone | Contact phone with the country code. 253 * @param string $sender | Origin number in digits; empty uses the first connected sender. 254 * @return array{state:string,expires_at:string,remaining_seconds:int} 255 */ 256 function joinotify_get_whatsapp_window( string $phone, string $sender = '' ) { 257 return Contact_Window::get( $phone, $sender ); 82 258 } 83 259 … … 423 599 * Get a Joinotify plugin setting value. 424 600 * 425 * @since 2.0.0 601 * The Joinotify API key (`whatsapp_cloud_api_token`) is stored sealed since 2.6.0 602 * and may come from the `JOINOTIFY_CLOUD_API_TOKEN` constant, so it is answered 603 * through Helpers::cloud_api_token(), in the clear, as before. 604 * 605 * @since 2.0.0 606 * @version 2.6.0 426 607 * @param string $key | Setting key. 427 608 * @return mixed Setting value, or false when the key is not set. 428 609 */ 429 610 function joinotify_get_setting( $key ) { 611 if ( 'whatsapp_cloud_api_token' === $key ) { 612 if ( false === Admin::get_setting( $key ) && ! Helpers::cloud_api_token_locked() ) { 613 return false; 614 } 615 616 return Helpers::cloud_api_token(); 617 } 618 430 619 return Admin::get_setting( $key ); 431 620 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)