Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Add in SendGrid Stats #157

Merged
merged 13 commits into from
Jun 25, 2024
2 changes: 1 addition & 1 deletion blocks/button/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function wp_newsletter_builder_button_block_init() {
function wp_newsletter_builder_button_block_init(): void {
// Register the block by passing the location of block.json.
register_block_type(
__DIR__
Expand Down
2 changes: 1 addition & 1 deletion blocks/divider/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function wp_newsletter_builder_divider_block_init() {
function wp_newsletter_builder_divider_block_init(): void {
// Register the block by passing the location of block.json.
register_block_type(
__DIR__
Expand Down
2 changes: 1 addition & 1 deletion blocks/heading/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function wp_newsletter_builder_heading_block_init() {
function wp_newsletter_builder_heading_block_init(): void {
// Register the block by passing the location of block.json.
register_block_type(
__DIR__
Expand Down
2 changes: 1 addition & 1 deletion blocks/list/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function wp_newsletter_builder_list_block_init() {
function wp_newsletter_builder_list_block_init(): void {
// Register the block by passing the location of block.json.
register_block_type(
__DIR__
Expand Down
2 changes: 1 addition & 1 deletion blocks/paragraph/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
*
* @see https://developer.wordpress.org/reference/functions/register_block_type/
*/
function wp_newsletter_builder_paragraph_block_init() {
function wp_newsletter_builder_paragraph_block_init(): void {
// Register the block by passing the location of block.json.
register_block_type(
__DIR__
Expand Down
47 changes: 47 additions & 0 deletions hooks/useNewsletterStats/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useCallback, useEffect, useState } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';

interface Stats {
Bounced?: number;
Clicks?: number;
Forwards?: number;
Likes?: number;
Mentions?: number;
Name?: string;
Recipients?: number;
SpamComplaints?: number;
Status?: string;
TotalOpened?: number;
UniqueOpened?: number;
Unsubscribed?: number;
WebVersionTextURL?: string;
WebVersionURL?: string;
WorldviewURL?: string;
}

function useNewsletterStats(newsletterId: string) {
const [stats, setStats] = useState<Stats>({});
const [fetching, setFetching] = useState(false);

const fetchStats = useCallback(async () => {
setFetching(true);
const res = await apiFetch({
path: `/wp-newsletter-builder/v1/status/${newsletterId}`,
});
setStats(res as Stats);
setFetching(false);
}, [newsletterId]);

useEffect(() => {
fetchStats();
}, [fetchStats]);

return {
validStats: stats.Status && stats.Name,
stats,
fetching,
fetchStats,
};
}

export default useNewsletterStats;
3 changes: 0 additions & 3 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@ parameters:
# Level 9 is the highest level
level: max

# Disable generics in type hints.
checkGenericClassInNonGenericObjectType: false

paths:
- blocks/
- entries/
Expand Down
78 changes: 35 additions & 43 deletions plugins/newsletter-status/newsletterStatusPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,63 +1,55 @@
import React, { useCallback, useEffect, useState } from '@wordpress/element';
import React from '@wordpress/element';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { __ } from '@wordpress/i18n';
import { select } from '@wordpress/data';
import apiFetch from '@wordpress/api-fetch';
import { Button } from '@wordpress/components';
import NewsletterSpinner from '@/components/newsletterSpinner';

interface Status {
Bounced?: number;
Clicks?: number;
Forwards?: number;
Likes?: number;
Mentions?: number;
Name?: string;
Recipients?: number;
SpamComplaints?: number;
Status?: string;
TotalOpened?: number;
UniqueOpened?: number;
Unsubscribed?: number;
WebVersionTextURL?: string;
WebVersionURL?: string;
WorldviewURL?: string;
}
import useNewsletterStatus from '@/hooks/useNewsletterStats';

export default function NewsletterStatusPanel() {
// @ts-ignore
const postId = select('core/editor').getCurrentPostId();

const [status, setStatus] = useState<Status>({});
const [fetching, setFetching] = useState(false);

const fetchStatus = useCallback(async () => {
setFetching(true);
const res = await apiFetch({
path: `/wp-newsletter-builder/v1/status/${postId}`,
});
setStatus(res as Status);
setFetching(false);
}, [postId]);

useEffect(() => {
fetchStatus();
}, [fetchStatus]);
const {
stats,
fetching,
fetchStats,
validStats,
} = useNewsletterStatus(postId);

const {
Status: statusString = '',
Name = '',
Recipients = null,
TotalOpened = null,
UniqueOpened = null,
} = status;
Recipients = '',
TotalOpened = '',
UniqueOpened = '',
} = stats;

if (!validStats && !fetching) {
return (
<PluginDocumentSettingPanel
name="rubric-selection"
title={__('Newsletter Stats', 'wp-newsletter-builder')}
>
<p>
{__('Newsletter stats not available. Try clicking the Refresh button.', 'wp-newsletter-builder')}
</p>
<Button
onClick={fetchStats}
variant="secondary"
disabled={fetching}
>
{__('Refresh', 'wp-newsletter-builder')}
</Button>
</PluginDocumentSettingPanel>
);
}

return (
<PluginDocumentSettingPanel
name="rubric-selection"
title={__('Newsletter Status', 'wp-newsletter-builder')}
title={__('Newsletter Stats', 'wp-newsletter-builder')}
>
{status ? (
{validStats ? (
<>
<dl>
<dt>
Expand Down Expand Up @@ -92,7 +84,7 @@ export default function NewsletterStatusPanel() {
</dd>
</dl>
<Button
onClick={fetchStatus}
onClick={fetchStats}
variant="secondary"
disabled={fetching}
>
Expand Down
4 changes: 3 additions & 1 deletion src/class-rest-api-endpoints.php
Original file line number Diff line number Diff line change
Expand Up @@ -190,18 +190,20 @@ public function get_status( WP_REST_Request $request ): array {
'Status' => __( 'Not sent', 'wp-newsletter-builder' ),
];
}

global $newsletter_builder_email_provider;
if ( empty( $newsletter_builder_email_provider ) || ! $newsletter_builder_email_provider instanceof Email_Providers\Email_Provider ) {
return [
'Status' => __( 'No email provider selected for WP Newsletter Builder.', 'wp-newsletter-builder' ),
];
}
$status = $newsletter_builder_email_provider->get_campaign_summary( $campaign_id );
if ( ! empty( $status ) && is_array( $status['response'] ) && 200 === $status['http_status_code'] ) {
if ( ! empty( $status ) && is_array( $status['response'] ) && $status['success'] ) {
$status['response']['Status'] = __( 'Sent' ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
wp_cache_set( $cache_key, $status['response'], '', 5 * MINUTE_IN_SECONDS );
return $status['response'];
}

$send_result = get_post_meta( $post_id, 'nb_newsletter_send_result', true );
if ( ! empty( $send_result ) && is_array( $send_result ) ) {
if ( is_string( $send_result['response'] ) && ( 200 > $send_result['http_status_code'] || 300 <= $send_result['http_status_code'] ) ) {
Expand Down
6 changes: 3 additions & 3 deletions src/email-providers/class-campaign-monitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public function create_campaign( int $newsletter_id, array $list_ids, string $ca
* @param string $campaign_id The campaign id.
* @return array{
* response: mixed,
* http_status_code: int,
* success: boolean,
* }|false The response from the API.
*/
public function send_campaign( string $campaign_id ): array|false {
Expand All @@ -184,8 +184,8 @@ public function send_campaign( string $campaign_id ): array|false {
);

return [
'response' => $result->response,
'http_status_code' => $result->http_status_code,
'response' => $result->response,
'success' => 200 === $result->http_status_code,
];
}

Expand Down
31 changes: 18 additions & 13 deletions src/email-providers/class-sendgrid.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,27 +241,33 @@ public function send_campaign( string $campaign_id ): array|false {
* @param string $campaign_id The campaign id.
* @return array{
* response: mixed,
* http_status_code: int,
* success: boolean,
* }|false The response from the API.
*
* @todo: Get recipients, total opened, unique opened.
*/
public function get_campaign_summary( string $campaign_id ): array|false {
$sg = $this->get_client();
if ( empty( $sg ) ) {
return false;
}
$response = $sg->client->marketing()->singlesends()->_( $campaign_id )->get();
$body = (object) json_decode( $response->body() );
$campaign_response = $sg->client->marketing()->singlesends()->_( $campaign_id )->get();
$stats_response = $sg->client->marketing()->stats()->singlesends()->_( $campaign_id )->get();

if ( 200 !== $stats_response->statusCode() || 200 !== $campaign_response->statusCode() ) {
return false;
}

$campaign_body = (object) json_decode( $campaign_response->body() );
$stats_body = (object) json_decode( $stats_response->body() );

return [
'response' => [
'Status' => $body->status,
'Name' => $body->name,
'Recipients' => 'N/A',
'TotalOpened' => 'N/A',
'UniqueOpened' => 'N/A',
'response' => [
'Status' => $campaign_body?->status ?? '',
'Name' => $campaign_body?->name ?? '',
'Recipients' => $stats_body->results[0]?->stats?->delivered ?? '',
'TotalOpened' => $stats_body->results[0]?->stats?->opens ?? '',
'UniqueOpened' => $stats_body->results[0]?->stats?->unique_opens ?? '',
],
'http_status_code' => $response->statusCode(),
'success' => true,
];
}

Expand Down Expand Up @@ -416,7 +422,6 @@ private function get_content( $post_id ) {

// Capture template output for the new query.
ob_start();
// @phpstan-ignore-next-line
load_template( WP_PLUGIN_DIR . '/wp-newsletter-builder/single-nb_newsletter.php' );
$content = ob_get_clean();

Expand Down
2 changes: 1 addition & 1 deletion src/email-providers/interface-email-provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public function send_campaign( string $campaign_id ): array|false;
* @param string $campaign_id The campaign id.
* @return array{
* response: mixed,
* http_status_code: int,
* success: boolean,
* }|false The response from the API.
*/
public function get_campaign_summary( string $campaign_id ): array|false;
Expand Down