PluginProbe ʕ •ᴥ•ʔ
Brevo – Email, SMS, Web Push, Chat, and more. / 3.2.2
Brevo – Email, SMS, Web Push, Chat, and more. v3.2.2
2.9.13 2.9.14 2.9.15 2.9.16 2.9.17 2.9.18 2.9.4 2.9.5 2.9.6 2.9.7 2.9.8 2.9.9 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.9 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.2 3.1.20 3.1.21 3.1.22 3.1.23 3.1.24 3.1.25 3.1.26 3.1.27 3.1.28 3.1.29 3.1.3 3.1.30 3.1.31 3.1.32 3.1.33 3.1.34 3.1.35 3.1.36 3.1.37 3.1.38 3.1.39 3.1.4 3.1.40 3.1.41 3.1.42 3.1.43 3.1.44 3.1.45 3.1.46 3.1.47 3.1.48 3.1.49 3.1.5 3.1.50 3.1.51 3.1.52 3.1.53 3.1.54 3.1.55 3.1.56 3.1.57 3.1.58 3.1.59 3.1.6 3.1.60 3.1.61 3.1.62 3.1.63 3.1.64 3.1.65 3.1.66 3.1.67 3.1.68 3.1.69 3.1.7 3.1.70 3.1.71 3.1.72 3.1.73 3.1.74 3.1.75 3.1.76 3.1.77 3.1.78 3.1.79 3.1.8 3.1.80 3.1.81 3.1.82 3.1.83 3.1.84 3.1.85 3.1.86 3.1.87 3.1.88 3.1.89 3.1.9 3.1.90 3.1.91 3.1.92 3.1.93 3.1.94 3.1.95 3.1.96 3.1.97 3.1.98 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 trunk 1.0 1.5 2.0.8 2.9.10 2.9.11 2.9.12
mailin / inc / push-api.php
mailin / inc Last commit date
templates 1 year ago SendinblueAccount.php 1 year ago SendinblueApiClient.php 1 year ago function.wp_mail.php 8 years ago http-build-url.php 1 year ago index.php 8 years ago mailin.php 3 years ago push-admin.php 1 year ago push-amp.php 1 year ago push-api.php 1 year ago push-httpclient.php 1 year ago push-public.php 1 year ago push-settings.php 1 year ago push-utils.php 1 year ago push-woocommerce.php 1 year ago sendinblue.php 3 years ago sib-api-manager.php 1 year ago sib-form-preview.php 2 years ago sib-sms-code.php 3 years ago table-forms.php 1 year ago
push-api.php
519 lines
1 <?php
2 if (!defined( 'ABSPATH' )) { http_response_code(403); exit(); }
3
4 if ( ! class_exists( 'SIB_Push_API' ) ) {
5 class SIB_Push_API {
6
7 const NONCE_ACTION = 'ajax_sib_admin_nonce';
8 const ADMIN_ACCESS = 'admin';
9 const EDITOR_ACCESS = 'editor';
10 private static $nonce = null;
11
12 public static function init() {
13 add_action( 'wp_ajax_sib_get_push_configuration', array( 'SIB_Push_API', 'ajax_get_push_configuration' ) );
14 add_action( 'wp_ajax_sib_update_push_configuration', array( 'SIB_Push_API', 'ajax_update_push_configuration' ) );
15 add_action( 'wp_ajax_sib_push_get_post_metadata', array('SIB_Push_API', 'ajax_get_post_metadata'));
16 add_action( 'wp_ajax_sib_push_set_push_activated', array('SIB_Push_API', 'ajax_set_push_activated'));
17 add_action( 'wp_ajax_sib_push_management_api', array('SIB_Push_API', 'ajax_management_api'));
18 add_action( 'wp_ajax_sib_push_upload', array('SIB_Push_API', 'ajax_upload'));
19 add_action( 'wp_ajax_sib_push_force_create_cart_reminder_campaign', array('SIB_Push_API', 'ajax_force_create_cart_reminder_campaign'));
20 self::prepare();
21 }
22
23 private static function prepare() {
24 $settings = SIB_Push_Settings::getSettings();
25 $credentials = $settings->getWonderPushCredentials();
26 if (!$credentials) return;
27 try {
28 if ( !$settings->getShowPush() ) {
29 $settings->setShowPush ( SIB_Push_Utils::get_show_push() );
30 if ( $settings->getShowPush() ) $settings->save();
31 }
32 if ( get_transient( 'sib_push_prepare_' . md5( SIB_Manager::$access_key ) ) === 'prepared' ) {
33 return;
34 }
35 if ( SIB_Push_Utils::get_push_application() ) {
36 return;
37 }
38 set_transient( 'sib_push_prepare_' . md5( SIB_Manager::$access_key ), 'prepared', 86400 );
39 SIB_Push_Utils::create_push_application( 'prepare' );
40 $settings->save();
41 } catch ( \WonderPush\Errors\Server $e ) {
42 $code = $e->getResponse() ? $e->getResponse()->getStatusCode() : null;
43 if ( $code !== 429 ) {
44 SIB_Push_Utils::log_error( 'Error creating application', $e );
45 } else {
46 // SIB_Push_Utils::log_debug( 'Refusing to create application', $e );
47 }
48 } catch ( SIB_Push_MissingCredentialsException $e) {
49 // Ignore
50 } catch ( Exception $e ) {
51 SIB_Push_Utils::log_debug('Error creating application', $e);
52 }
53 }
54
55 public static function get_nonce() {
56 if (self::$nonce === null) self::$nonce = wp_create_nonce(self::NONCE_ACTION);
57 return self::$nonce;
58 }
59
60 private static function verify_nonce() {
61 $nonce = '';
62 if ($_SERVER['REQUEST_METHOD'] === 'POST') {
63 $nonce = $_POST['nonce'];
64 } else if ($_SERVER['REQUEST_METHOD'] === 'GET') {
65 $nonce = $_GET['nonce'];
66 }
67 if (!$nonce || !wp_verify_nonce($nonce, self::NONCE_ACTION)) {
68 wp_die('Forbidden', 403);
69 }
70 }
71
72 private static function verify_access($access_type = SIB_Push_API::ADMIN_ACCESS) {
73 self::verify_nonce();
74 if ($access_type === SIB_Push_API::EDITOR_ACCESS) {
75 if (!SIB_Push_Utils::can_send_notifications()) {
76 wp_die('Forbidden', 403);
77 }
78 } else {
79 if (!SIB_Push_Utils::can_modify_settings()) {
80 wp_die('Forbidden', 403);
81 }
82 }
83 }
84
85 private static function returnResult($result) {
86 header('Content-Type: application/json');
87 $json = json_encode($result);
88 echo $json;
89 wp_die();
90 }
91
92 private static function returnError($msg, $statusCode) {
93 header('Content-Type: application/json');
94 wp_die(json_encode(array(
95 'error' => array(
96 'message' => $msg,
97 'code' => $statusCode,
98 ),
99 )), $statusCode);
100 }
101
102 public static function ajax_upload() {
103 self::verify_access();
104 $settings = SIB_Push_Settings::getSettings();
105 $credentials = $settings->getWonderPushCredentials();
106 try {
107 $app = SIB_Push_Utils::get_push_application(SIB_Push_Utils::DEFAULT_CACHE_TTL);
108 } catch (Exception $e) {
109 SIB_Push_Utils::log_error('Could not get application', $e);
110 self::returnError('Could not get application', 500);
111 }
112 $wp = SIB_Push_Utils::management_api_client($credentials);
113 $request = $wp->rest()->request('POST', 'applications/' . urlencode($app->getId()) . '/upload');
114 $image = $_FILES['image'];
115 if (!$image) {
116 self::returnError('Missing image', 400);
117 }
118 $request->addFile('image', $image['name'], $image['tmp_name'], $image['type']);
119 $response = $wp->rest()->execute($request);
120 $responseHeaders = $response->getHeaders();
121 if (isset($responseHeaders['content-type'])) {
122 header('Content-Type: ' . $responseHeaders['content-type']);
123 }
124 wp_die($response->getRawBody(), $response->getStatusCode());
125 }
126
127 public static function ajax_management_api() {
128 self::verify_access();
129 $method = isset($_POST['method']) ? $_POST['method'] : null;
130 $url = isset($_POST['url']) ? $_POST['url'] : null;
131 $body = isset($_POST['body']) ? wp_unslash($_POST['body']) : null;
132
133 switch ($method) {
134 case \WonderPush\Net\Request::GET:
135 case \WonderPush\Net\Request::PUT:
136 case \WonderPush\Net\Request::POST:
137 case \WonderPush\Net\Request::PATCH:
138 case \WonderPush\Net\Request::DELETE:
139 break;
140 default:
141 $method = null;
142 }
143 if (!$method || !$url) {
144 self::returnError('Missing method or url', 400);
145 }
146 $params = $body !== null ? json_decode($body, false) : array();
147 if (json_last_error()) {
148 self::returnError('Invalid JSON body', 400);
149 }
150
151 $settings = SIB_Push_Settings::getSettings();
152 $credentials = $settings->getWonderPushCredentials();
153
154 $wp = SIB_Push_Utils::management_api_client($credentials);
155
156 $request = $wp->rest()->request($method, '../../' . $url, $params);
157 $response = $wp->rest()->execute($request);
158 $responseHeaders = $response->getHeaders();
159 if (isset($responseHeaders['content-type'])) {
160 header('Content-Type: ' . $responseHeaders['content-type']);
161 }
162
163 // Intercept certain calls. We'll have to treat the special wonderpush/v1/batch as well
164 $reqsToCheck = array();
165 if ($method === 'POST' && $url === 'wonderpush/v1/batch' && isset($params->requests)) {
166 $reqsToCheck = array_map(function ($req) { return array($req->method, 'wonderpush'.$req->path); }, $params->requests);
167 } else {
168 $reqsToCheck = array(array($method, $url));
169 }
170
171 foreach ($reqsToCheck as $req) {
172 $reqMethod = $req[0];
173 $reqUrl = $req[1];
174 // Intercept cart reminder campaign update to clear the cache
175 // NOTE: deactivate woocommerce
176 $cartReminderCampaign = null;
177 // $cartReminderCampaign = SIB_Push_WooCommerce::ensure_cart_reminder_campaign_exists();
178 if ($cartReminderCampaign && ($reqMethod === 'PATCH' || $reqMethod === 'DELETE') && str_starts_with($reqUrl, 'wonderpush/v1/campaigns/'.$cartReminderCampaign->getId())) {
179 try {
180 // SIB_Push_Utils::log_debug('Clearing cart reminder cache');
181 SIB_Push_WooCommerce::clear_cart_reminder_campaign_cache();
182 } catch ( Exception $e ) {
183 SIB_Push_Utils::log_error('Could not clear cart reminder cache', $e);
184 }
185 }
186
187 // Intercept application updates to clear the cache
188 if ($reqMethod === 'PATCH' && str_starts_with($reqUrl, 'wonderpush/v1/applications/')) {
189 $app = SIB_Push_Utils::get_push_application();
190 if ($app && $reqUrl === 'wonderpush/v1/applications/' . $app->getId()) {
191 try {
192 // SIB_Push_Utils::log_debug('Clearing application cache');
193 SIB_Push_Utils::clear_push_application_cache();
194 } catch ( Exception $e ) {
195 SIB_Push_Utils::log_error('Could not clear application cache', $e);
196 }
197 }
198 }
199 }
200
201 wp_die($response->getRawBody(), $response->getStatusCode());
202 }
203
204 public static function ajax_set_push_activated() {
205 self::verify_access();
206 if (array_key_exists('activated', $_POST)) {
207 try {
208 $app = null;
209 if ($_POST['activated'] === 'true') {
210 $app = SIB_Push_Utils::activate_push();
211 if ($app && $app->getStatus() === 'creation') {
212 $app = SIB_Push_Utils::pollApplicationCreation();
213 }
214 } else {
215 SIB_Push_Utils::deactivate_push();
216 }
217 self::returnResult(array('application' => $app, 'configuration' => self::get_push_configuration()));
218 } catch (Exception $e) {
219 self::returnError($e->getMessage(), 500);
220 }
221 }
222 }
223
224 public static function get_push_configuration() {
225 $settings = SIB_Push_Settings::getSettings();
226 $app = SIB_Push_Utils::get_push_application();
227 return (object)array(
228 'applicationId' => $app && $app->getId() ? $app->getId() : null,
229 'websiteUrl' => get_site_url(),
230 'websiteName' => get_bloginfo('name'),
231 'pushOptions' => SIB_Push_Utils::wonderpush_init_options(),
232 'imgUrl' => plugins_url('img', dirname(__FILE__)),
233 'bypassWordPressHttpClient' => $settings->getBypassWordPressHttpClient(),
234 'deliveryTimeSeconds' => $settings->getDeliveryTimeSeconds(),
235 'notificationTitle' => $settings->getNotificationTitle(),
236 'defaultTargetSegmentId' => (int)$settings->getDefaultTargetSegmentId() ?: null,
237 'defaultTargetListId' => (int)$settings->getDefaultTargetListId() ?: null,
238 'additionalCustomPostTypes' => $settings->getAdditionalCustomPostTypes(),
239 'disableSendOnPublish' => $settings->getDisableSendOnPublish(),
240 'disableSendByDefaultOnPublish' => $settings->getDisableSendByDefaultOnPublish(),
241 'sendOnThirdPartyPublish' => $settings->getSendOnThirdPartyPublish(),
242 'disableFeedbackOnPublish' => $settings->getDisableFeedbackOnPublish(),
243 'disableUsePostImageForNotification' => $settings->getDisableUsePostImageForNotification(),
244 'preferLargeImageForNotification' => $settings->getPreferLargeImageForNotification(),
245 'cartReminderCampaignId' => $settings->getCartReminderCampaignId(),
246 'enableOrderCompleteNotifications' => $settings->getEnableOrderCompleteNotifications(),
247 'orderCompleteNotificationsMessage' => $settings->getOrderCompleteNotificationsMessage(),
248 'enableOrderProcessingNotifications' => $settings->getEnableOrderProcessingNotifications(),
249 'orderProcessingNotificationsMessage' => $settings->getOrderProcessingNotificationsMessage(),
250 'disableThankYouEvent' => $settings->getDisableThankYouEvent(),
251 'thankYouEventName' => $settings->getThankYouEventName(),
252 'disableAmpUnsubscribe' => $settings->getDisableAmpUnsubscribe(),
253 'ampSubscribeButtonLabel' => $settings->getAmpSubscribeButtonLabel(),
254 'ampUnsubscribeButtonLabel' => $settings->getAmpUnsubscribeButtonLabel(),
255 'disableAmpBottomSubscribeButton' => $settings->getDisableAmpBottomSubscribeButton(),
256 'disableAmpTopSubscribeButton' => $settings->getDisableAmpTopSubscribeButton(),
257 'ampButtonWidth' => (int)$settings->getAmpButtonWidth(),
258 'ampButtonHeight' => (int)$settings->getAmpButtonHeight(),
259 'additionalInitOptionsJson' => $settings->getAdditionalInitOptionsJson(),
260 'hideAdminBarShortcut' => $settings->getHideAdminBarShortcut(),
261 );
262 }
263
264 public static function ajax_get_push_configuration() {
265 self::verify_access();
266 self::returnResult(self::get_push_configuration());
267 }
268
269 public static function ajax_update_push_configuration() {
270 self::verify_access();
271 $settings = SIB_Push_Settings::getSettings();
272 $save = false;
273 // Boolean props
274 foreach (array(
275 'bypassWordPressHttpClient',
276 'disableSendOnPublish',
277 'disableSendByDefaultOnPublish',
278 'sendOnThirdPartyPublish',
279 'disableFeedbackOnPublish',
280 'disableUsePostImageForNotification',
281 'preferLargeImageForNotification',
282 'enableOrderCompleteNotifications',
283 'enableOrderProcessingNotifications',
284 'disableAmpUnsubscribe',
285 'disableAmpBottomSubscribeButton',
286 'disableAmpTopSubscribeButton',
287 'disableThankYouEvent',
288 'hideAdminBarShortcut',
289 ) as $key) {
290 if (array_key_exists($key, $_POST)) {
291 $settings->{"set" . ucfirst($key)}($_POST[$key] === 'true');
292 $save = true;
293 }
294 }
295 // Notification title
296 if (array_key_exists('notificationTitle', $_POST)) {
297
298 // Sanitize user input
299 $value = $_POST['notificationTitle']
300 ? stripslashes(trim(sanitize_text_field($_POST['notificationTitle']))) : '';
301
302 // Validate user input
303 $value = $value && strlen($value) > 1024 ? substr($value, 0, 1024) : $value;
304
305 $settings->setNotificationTitle($value);
306 $save = true;
307 }
308 // Default target segment ID
309 if (array_key_exists('defaultTargetSegmentId', $_POST)) {
310
311 // Sanitize user input
312 $value = $_POST['defaultTargetSegmentId']
313 ? (int)trim(sanitize_text_field($_POST['defaultTargetSegmentId'])) : null;
314
315 // Validate
316 $value = is_int($value) ? $value : null;
317
318 $settings->setDefaultTargetSegmentId($value);
319 $save = true;
320 }
321 // Default target list ID
322 if (array_key_exists('defaultTargetListId', $_POST)) {
323
324 // Sanitize user input
325 $value = $_POST['defaultTargetListId']
326 ? (int)trim(sanitize_text_field($_POST['defaultTargetListId'])) : null;
327
328 // Validate
329 $value = is_int($value) ? $value : null;
330
331 $settings->setDefaultTargetListId($value);
332 $save = true;
333 }
334 // Additional custom post types
335 if (array_key_exists('additionalCustomPostTypes', $_POST)) {
336
337 // Sanitize user input
338 $value = $_POST['additionalCustomPostTypes']
339 ? stripslashes(trim(sanitize_text_field($_POST['additionalCustomPostTypes']))) : '';
340
341 // Validate user input
342 $value = $value && strlen($value) > 1024 ? substr($value, 0, 1024) : $value;
343
344 $settings->setAdditionalCustomPostTypes($value);
345 $save = true;
346 }
347 // Order confirmation notifications message
348 if (array_key_exists('orderCompleteNotificationsMessage', $_POST)) {
349
350 // Sanitize user input
351 $value = $_POST['orderCompleteNotificationsMessage']
352 ? stripslashes(trim(sanitize_text_field($_POST['orderCompleteNotificationsMessage']))) : '';
353
354 // Validate user input
355 $value = $value && strlen($value) > 1024 ? substr($value, 0, 1024) : $value;
356
357 $settings->setOrderCompleteNotificationsMessage($value);
358 $save = true;
359 }
360 // Order confirmation notifications message
361 if (array_key_exists('orderProcessingNotificationsMessage', $_POST)) {
362 // Sanitize user input
363 $value = $_POST['orderProcessingNotificationsMessage']
364 ? stripslashes(trim(sanitize_text_field($_POST['orderProcessingNotificationsMessage']))) : '';
365
366 // Validate user input
367 $value = $value && strlen($value) > 1024 ? substr($value, 0, 1024) : $value;
368
369 $settings->setOrderProcessingNotificationsMessage($value);
370 $save = true;
371 }
372
373 // Thank you event name
374 if (array_key_exists('thankYouEventName', $_POST)) {
375 // Sanitize user input
376 $value = $_POST['thankYouEventName']
377 ? trim(sanitize_text_field($_POST['thankYouEventName'])) : '';
378
379 // Validate user input
380 $value = $value && strlen($value) > 256 ? substr($value, 0, 256) : $value;
381
382 $settings->setThankYouEventName($value);
383 $save = true;
384 }
385
386 // Additional init options
387 if (array_key_exists('additionalInitOptionsJson', $_POST)) {
388 // Sanitize user input
389 $value = $_POST['additionalInitOptionsJson']
390 ? stripslashes(trim(sanitize_text_field($_POST['additionalInitOptionsJson']))) : null;
391
392 // Validate user input
393 if ($value && strlen($value) > 2048) {
394 self::returnError(__('Additional init options JSON cannot be larger than 2048 bytes.'), 400);
395 return;
396 }
397 // Validate JSON
398 if ($value) {
399 $jsonValue = json_decode($value);
400 if (json_last_error()) {
401 self::returnError(__('Additional init options JSON must be valid JSON: ' + json_last_error_msg()), 400);
402
403 }
404 if (!is_object($jsonValue) && $jsonValue !== null) {
405 self::returnError(__('Additional init options JSON must be an object or null.'), 400);
406 return;
407 }
408 }
409 $value = $value ?: '';
410
411 $settings->setAdditionalInitOptionsJson($value);
412 $save = true;
413 }
414 // AMP Subscribe button label
415 if (array_key_exists('ampSubscribeButtonLabel', $_POST)) {
416 // Sanitize user input
417 $value = $_POST['ampSubscribeButtonLabel']
418 ? trim(sanitize_text_field($_POST['ampSubscribeButtonLabel'])) : '';
419
420 // Validate user input
421 $value = $value && strlen($value) > 1024 ? substr($value, 0, 1024) : $value;
422
423 $settings->setAmpSubscribeButtonLabel($value);
424 $save = true;
425 }
426 // AMP Unsubscribe button label
427 if (array_key_exists('ampUnsubscribeButtonLabel', $_POST)) {
428 // Sanitize user input
429 $value = $_POST['ampUnsubscribeButtonLabel']
430 ? trim(sanitize_text_field($_POST['ampUnsubscribeButtonLabel'])) : '';
431
432 // Validate user input
433 $value = $value && strlen($value) > 1024 ? substr($value, 0, 1024) : $value;
434
435 $settings->setAmpUnsubscribeButtonLabel($value);
436 $save = true;
437 }
438 // AMP Button width
439 if (array_key_exists('ampButtonWidth', $_POST)) {
440
441 // Sanitize
442 $value = $_POST['ampButtonWidth']
443 ? (int)trim(sanitize_text_field($_POST['ampButtonWidth'])) : null;
444
445 // Validate
446 $value = is_int($value) ? $value : null;
447
448 $settings->setAmpButtonWidth($value);
449 $save = true;
450 }
451 // AMP Button height
452 if (array_key_exists('ampButtonHeight', $_POST)) {
453
454 // Sanitize
455 $value = $_POST['ampButtonHeight']
456 ? (int)trim(sanitize_text_field($_POST['ampButtonHeight'])) : null;
457
458 // Validate
459 $value = is_int($value) ? $value : null;
460
461 $settings->setAmpButtonHeight($value);
462 $save = true;
463 }
464 // Delivery time seconds
465 if (array_key_exists('deliveryTimeSeconds', $_POST)) {
466
467 // Sanitize
468 $value = $_POST['deliveryTimeSeconds']
469 ? (int)trim(sanitize_text_field($_POST['deliveryTimeSeconds'])) : null;
470
471 // Validate
472 $value = is_int($value) ? $value : null;
473
474 $settings->setDeliveryTimeSeconds($value);
475 $save = true;
476 }
477 if ($save) $settings->save();
478 // NOTE: deactivate woocommerce
479 // SIB_Push_WooCommerce::ensure_cart_reminder_campaign_exists();
480 self::ajax_get_push_configuration();
481 }
482
483 public static function ajax_get_post_metadata() {
484 self::verify_access(SIB_Push_API::EDITOR_ACCESS);
485 $post_id = intval($_GET['post_id']);
486
487 if(is_null($post_id)){
488 self::returnError('Provide post_id query paramter', 400);
489 return;
490 }
491
492 $info = get_post_meta($post_id, SIB_Push_Admin::POST_META_INFO_MESSAGE);
493 if(is_array($info)){
494 $info = $info ? $info[0] : null;
495 }
496
497 $error = get_post_meta($post_id, SIB_Push_Admin::POST_META_ERROR_MESSAGE);
498 if(is_array($error)){
499 $error = $error ? $error[0] : null;
500 }
501
502 // reset meta
503 delete_post_meta($post_id, SIB_Push_Admin::POST_META_INFO_MESSAGE);
504 delete_post_meta($post_id, SIB_Push_Admin::POST_META_ERROR_MESSAGE);
505
506 self::returnResult((object)array('error_message' => $error, 'info_message' => $info));
507 }
508
509 public static function ajax_force_create_cart_reminder_campaign() {
510 self::verify_access();
511 if ($_SERVER['REQUEST_METHOD'] !== 'POST') self::returnError('Method not allowed', 405);
512 $campaign = SIB_Push_WooCommerce::ensure_cart_reminder_campaign_exists(true);
513 self::returnResult(array('success' => true, 'campaign' => $campaign->toData()));
514 }
515
516 }
517
518 }
519