Skip to content

Commit 0c3acae

Browse files
authored
Merge pull request #209 from netflie/single-product-message
Single product message
2 parents 3c3aea9 + 11e8cb5 commit 0c3acae

File tree

7 files changed

+209
-1
lines changed

7 files changed

+209
-1
lines changed

README.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ $whatsapp_cloud_api->sendCtaUrl(
257257

258258
$body = 'Hello! Thanks for your interest. Ordering is easy. Just visit our catalog and add items you\'d like to purchase.';
259259
$footer = 'Best grocery deals on WhatsApp!';
260-
$sku_thumbnail = '<product-sku-id>'; // product sku id to use as header thumbnail
260+
$sku_thumbnail = '<product-sku-id>'; // product sku id to use as header thumbnail
261261

262262
$whatsapp_cloud_api->sendCatalog(
263263
'<destination-phone-number>',
@@ -340,6 +340,24 @@ $whatsapp_cloud_api->sendMultiProduct(
340340
);
341341
```
342342

343+
### Send Single Product Message
344+
```php
345+
<?php
346+
347+
$catalog_id = '<catalog-id>';
348+
$sku_id = '<product-sku-id>';
349+
$body = 'Hello! Here\'s your requested product. Thanks for shopping with us.';
350+
$footer = 'Subject to T&C';
351+
352+
$whatsapp_cloud_api->sendSingleProduct(
353+
'<destination-phone-number>',
354+
$catalog_id,
355+
$sku_id,
356+
$body, // body: optional
357+
$footer // footer: optional
358+
);
359+
```
360+
343361
### Replying messages
344362

345363
You can reply a previous sent message:
@@ -502,6 +520,7 @@ Fields list: https://developers.facebook.com/docs/whatsapp/cloud-api/reference/b
502520
- Send Lists
503521
- Send Buttons
504522
- Send Multi Product Message
523+
- Send Single Product
505524
- Upload media resources to WhatsApp servers
506525
- Download media resources from WhatsApp servers
507526
- Mark messages as read
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Netflie\WhatsAppCloudApi\Message;
4+
5+
final class SingleProductMessage extends Message
6+
{
7+
/**
8+
* {@inheritdoc}
9+
*/
10+
protected string $type = 'product';
11+
12+
private int $catalog_id;
13+
14+
private string $product_retailer_id;
15+
16+
private ?string $body;
17+
18+
private ?string $footer;
19+
20+
/**
21+
* {@inheritdoc}
22+
*/
23+
public function __construct(string $to, int $catalog_id, string $product_retailer_id, ?string $body, ?string $footer, ?string $reply_to)
24+
{
25+
$this->catalog_id = $catalog_id;
26+
$this->product_retailer_id = $product_retailer_id;
27+
$this->body = $body;
28+
$this->footer = $footer;
29+
30+
parent::__construct($to, $reply_to);
31+
}
32+
33+
public function catalog_id(): int
34+
{
35+
return $this->catalog_id;
36+
}
37+
38+
public function product_retailer_id(): string
39+
{
40+
return $this->product_retailer_id;
41+
}
42+
43+
public function body(): ?string
44+
{
45+
return $this->body;
46+
}
47+
48+
public function footer(): ?string
49+
{
50+
return $this->footer;
51+
}
52+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Netflie\WhatsAppCloudApi\Request\MessageRequest;
4+
5+
use Netflie\WhatsAppCloudApi\Request\MessageRequest;
6+
7+
final class RequestSingleProductMessage extends MessageRequest
8+
{
9+
/**
10+
* {@inheritdoc}
11+
*/
12+
public function body(): array
13+
{
14+
$body = [
15+
'messaging_product' => $this->message->messagingProduct(),
16+
'recipient_type' => $this->message->recipientType(),
17+
'to' => $this->message->to(),
18+
'type' => 'interactive',
19+
'interactive' => [
20+
'type' => $this->message->type(),
21+
'action' => [
22+
'catalog_id' => $this->message->catalog_id(),
23+
'product_retailer_id' => $this->message->product_retailer_id(),
24+
],
25+
],
26+
];
27+
28+
if ($this->message->body()) {
29+
$body['interactive']['body'] = ['text' => $this->message->body()];
30+
}
31+
32+
if ($this->message->footer()) {
33+
$body['interactive']['footer'] = ['text' => $this->message->footer()];
34+
}
35+
36+
if ($this->message->replyTo()) {
37+
$body['context']['message_id'] = $this->message->replyTo();
38+
}
39+
40+
return $body;
41+
}
42+
}

src/WhatsAppCloudApi.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,32 @@ public function sendReaction(string $to, string $message_id, string $emoji = '')
512512
return $this->client->sendMessage($request);
513513
}
514514

515+
/**
516+
* Sends a single product message to a specified recipient.
517+
*
518+
* @param string $to The WhatsApp ID or phone number for the person you want to send the message to.
519+
* @param int $catalog_id The ID of the catalog where the product is located.
520+
* @param string $product_retailer_id The retailer-specific ID of the product.
521+
* @param string|null $body The body of the message. Defaults to an empty string if not provided.
522+
* @param string|null $footer The footer of the message. Defaults to an empty string if not provided.
523+
*
524+
* @return Response The response object containing the result of the API request.
525+
*
526+
* @throws Response\ResponseException If there is an error with the API request.
527+
*/
528+
public function sendSingleProduct(string $to, int $catalog_id, string $product_retailer_id, ?string $body = '', ?string $footer = '')
529+
{
530+
$message = new Message\SingleProductMessage($to, $catalog_id, $product_retailer_id, $body, $footer, $this->reply_to);
531+
$request = new Request\MessageRequest\RequestSingleProductMessage(
532+
$message,
533+
$this->app->accessToken(),
534+
$this->app->fromPhoneNumberId(),
535+
$this->timeout
536+
);
537+
538+
return $this->client->sendMessage($request);
539+
}
540+
515541
/**
516542
* Get Business Profile
517543
*

tests/Integration/WhatsAppCloudApiTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,25 @@ public function test_send_reaction_message()
390390
$this->assertEquals(false, $response->isError());
391391
}
392392

393+
public function test_send_single_product()
394+
{
395+
$catalog_id = WhatsAppCloudApiTestConfiguration::$catalog_id;
396+
$product_sku_id = WhatsAppCloudApiTestConfiguration::$product_sku_id;
397+
$body = 'Hello! Here\'s your requested product. Thanks for shopping with us.';
398+
$footer = 'Subject to T&C';
399+
400+
$response = $this->whatsapp_app_cloud_api->sendSingleProduct(
401+
WhatsAppCloudApiTestConfiguration::$to_phone_number_id,
402+
$catalog_id,
403+
$product_sku_id,
404+
$body, // body: optional
405+
$footer // footer: optional
406+
);
407+
408+
$this->assertEquals(200, $response->httpStatusCode());
409+
$this->assertEquals(false, $response->isError());
410+
}
411+
393412
public function test_send_remove_reaction_message()
394413
{
395414
$textMessage = $this->whatsapp_app_cloud_api->sendTextMessage(

tests/Unit/WhatsAppCloudApiTest.php

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,6 +1309,53 @@ public function test_send_multi_product()
13091309
$this->assertEquals(false, $response->isError());
13101310
}
13111311

1312+
public function test_send_single_product()
1313+
{
1314+
$to = $this->faker->phoneNumber;
1315+
$url = $this->buildMessageRequestUri();
1316+
$message = $this->faker->text(1024);
1317+
$footer = $this->faker->text(60);
1318+
$catalog_id = $this->faker->randomNumber();
1319+
$product_retailer_id = $this->faker->uuid();
1320+
1321+
$body = [
1322+
'messaging_product' => 'whatsapp',
1323+
'recipient_type' => 'individual',
1324+
'to' => $to,
1325+
'type' => 'interactive',
1326+
'interactive' => [
1327+
'type' => 'product',
1328+
'body' => ['text' => $message],
1329+
'footer' => ['text' => $footer],
1330+
'action' => [
1331+
'catalog_id' => $catalog_id,
1332+
'product_retailer_id' => $product_retailer_id,
1333+
],
1334+
],
1335+
];
1336+
$headers = [
1337+
'Authorization' => 'Bearer ' . $this->access_token,
1338+
];
1339+
1340+
$this->client_handler
1341+
->postJsonData($url, $body, $headers, Argument::type('int'))
1342+
->shouldBeCalled()
1343+
->willReturn(new RawResponse($headers, $this->successfulMessageNodeResponse(), 200));
1344+
1345+
$response = $this->whatsapp_app_cloud_api->sendSingleProduct(
1346+
$to,
1347+
$catalog_id,
1348+
$product_retailer_id,
1349+
$message,
1350+
$footer
1351+
);
1352+
1353+
$this->assertEquals(200, $response->httpStatusCode());
1354+
$this->assertEquals(json_decode($this->successfulMessageNodeResponse(), true), $response->decodedBody());
1355+
$this->assertEquals($this->successfulMessageNodeResponse(), $response->body());
1356+
$this->assertEquals(false, $response->isError());
1357+
}
1358+
13121359
public function test_mark_a_message_as_read()
13131360
{
13141361
$url = $this->buildMessageRequestUri();

tests/WhatsAppCloudApiTestConfiguration.php.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ class WhatsAppCloudApiTestConfiguration {
1717
public static $contact_phone_number = '';
1818
public static $contact_waid = '';
1919

20+
public static $catalog_id = '';
21+
public static $product_sku_id = '';
22+
2023
}

0 commit comments

Comments
 (0)