← All changes
|
modules/email-report/class-cartflows-admin-report-emails.php
+182
-3
3.1.1
→
3.3.0
View file →
| @@ -91,9 +91,9 @@ | ||
| 91 | 91 | wcf()->logger->log( 'Total Revenue: ' . $stats['total_revenue'] ); |
| 92 | 92 | |
| 93 | 93 | if ( isset( $stats['total_revenue_raw'] ) && $stats['total_revenue_raw'] > 0 ) { |
| 94 | 94 | |
| 95 | - $subject = $this->get_email_subject(); | |
| 95 | + $subject = $this->get_email_subject( $stats ); | |
| 96 | 96 | $headers = 'From: ' . get_bloginfo( 'name' ) . ' <' . get_option( 'admin_email' ) . '>' . "\r\n"; |
| 97 | 97 | $headers .= "Content-Type: text/html;\r\n"; |
| 98 | 98 | |
| 99 | 99 | $emails = preg_split( "/[\f\r\n]+/", $emails ); |
| @@ -172,15 +172,183 @@ | ||
| 172 | 172 | } |
| 173 | 173 | |
| 174 | 174 | /** |
| 175 | 175 | * Get admin report email subject. |
| 176 | + * | |
| 177 | + * @param array<string, mixed> $stats Weekly stats for revenue interpolation. | |
| 178 | + * @return string | |
| 176 | 179 | */ |
| 177 | - public function get_email_subject() { | |
| 180 | + public function get_email_subject( $stats = array() ) { | |
| 178 | 181 | |
| 179 | - return esc_html__( 'Here’s how your store performed last week!', 'cartflows' ); | |
| 182 | + // Strip wc_price() HTML wrappers and decode numeric entities (e.g. ₨ for ₨) so currency symbols render in plain-text subject lines. | |
| 183 | + $revenue = isset( $stats['total_revenue'] ) && is_string( $stats['total_revenue'] ) | |
| 184 | + ? html_entity_decode( wp_strip_all_tags( $stats['total_revenue'] ), ENT_QUOTES, 'UTF-8' ) | |
| 185 | + : ''; | |
| 186 | + | |
| 187 | + if ( '' === $revenue ) { | |
| 188 | + return esc_html__( 'Your weekly CartFlows report', 'cartflows' ); | |
| 189 | + } | |
| 190 | + | |
| 191 | + /* translators: %s: Total revenue earned in the last 7 days, formatted with currency. */ | |
| 192 | + return sprintf( esc_html__( 'Your weekly CartFlows report — %s earned', 'cartflows' ), $revenue ); | |
| 180 | 193 | } |
| 181 | 194 | |
| 182 | 195 | /** |
| 196 | + * Get a weekly tip for the "One thing to try this week" section. | |
| 197 | + * Rotates by ISO week so the same tip shows for all sends in the same week. | |
| 198 | + * | |
| 199 | + * @since 3.1.2 | |
| 200 | + * @param array<string, mixed> $stats Weekly stats (allows the filter to choose data-driven tips). | |
| 201 | + * @return array{headline: string, body: string} | |
| 202 | + */ | |
| 203 | + public function get_weekly_tip( $stats = array() ) { | |
| 204 | + | |
| 205 | + $tips = array( | |
| 206 | + array( | |
| 207 | + 'headline' => __( 'Add a one-click upsell to your top flow.', 'cartflows' ), | |
| 208 | + 'body' => __( 'Stores that add one see an average +12% lift in average order value.', 'cartflows' ), | |
| 209 | + ), | |
| 210 | + array( | |
| 211 | + 'headline' => __( 'Enable an order bump on your highest-traffic checkout.', 'cartflows' ), | |
| 212 | + 'body' => __( 'Order bumps consistently lift revenue per order with minimal effort.', 'cartflows' ), | |
| 213 | + ), | |
| 214 | + array( | |
| 215 | + 'headline' => __( 'Run an A/B test on your top-performing flow.', 'cartflows' ), | |
| 216 | + 'body' => __( 'Test a single change — headline, button, or image — and let the winner run.', 'cartflows' ), | |
| 217 | + ), | |
| 218 | + array( | |
| 219 | + 'headline' => __( 'Add a thank-you page upsell.', 'cartflows' ), | |
| 220 | + 'body' => __( 'Post-purchase offers convert better than pre-purchase upsells for many stores.', 'cartflows' ), | |
| 221 | + ), | |
| 222 | + array( | |
| 223 | + 'headline' => __( 'Streamline your checkout to a single column.', 'cartflows' ), | |
| 224 | + 'body' => __( 'Single-column checkouts reduce cognitive load and tend to convert better on mobile.', 'cartflows' ), | |
| 225 | + ), | |
| 226 | + array( | |
| 227 | + 'headline' => __( 'Send abandoned cart recovery emails.', 'cartflows' ), | |
| 228 | + 'body' => __( 'Most stores recover 8–15% of abandoned carts with a simple two-email sequence.', 'cartflows' ), | |
| 229 | + ), | |
| 230 | + array( | |
| 231 | + 'headline' => __( 'Use a countdown timer on limited-time offers.', 'cartflows' ), | |
| 232 | + 'body' => __( 'Urgency, when honest, lifts conversion on time-sensitive promotions.', 'cartflows' ), | |
| 233 | + ), | |
| 234 | + array( | |
| 235 | + 'headline' => __( 'Pre-fill checkout fields whenever possible.', 'cartflows' ), | |
| 236 | + 'body' => __( 'Each saved keystroke reduces friction at the highest-stakes step of the journey.', 'cartflows' ), | |
| 237 | + ), | |
| 238 | + ); | |
| 239 | + | |
| 240 | + $index = (int) gmdate( 'W' ) % count( $tips ); | |
| 241 | + $tip = $tips[ $index ]; | |
| 242 | + | |
| 243 | + /** | |
| 244 | + * Filter the weekly tip shown in the report email. | |
| 245 | + * | |
| 246 | + * @param array<string, mixed> $tip Default tip with 'headline' and 'body'. | |
| 247 | + * @param array<string, mixed> $stats Weekly stats. | |
| 248 | + */ | |
| 249 | + $filtered = apply_filters( 'cartflows_weekly_email_tip', $tip, $stats ); | |
| 250 | + | |
| 251 | + if ( | |
| 252 | + is_array( $filtered ) | |
| 253 | + && isset( $filtered['headline'], $filtered['body'] ) | |
| 254 | + && is_string( $filtered['headline'] ) | |
| 255 | + && is_string( $filtered['body'] ) | |
| 256 | + ) { | |
| 257 | + return array( | |
| 258 | + 'headline' => $filtered['headline'], | |
| 259 | + 'body' => $filtered['body'], | |
| 260 | + ); | |
| 261 | + } | |
| 262 | + | |
| 263 | + return $tip; | |
| 264 | + } | |
| 265 | + | |
| 266 | + /** | |
| 267 | + * Get top wins data (top flow, best step, top bump) for the highlights section. | |
| 268 | + * Free returns an empty array; Pro hooks the filter to return real data. | |
| 269 | + * | |
| 270 | + * @since 3.1.2 | |
| 271 | + * @param string $start_date Range start (Y-m-d). | |
| 272 | + * @param string $end_date Range end (Y-m-d). | |
| 273 | + * @return array<int, array{label?: string, detail?: string}> | |
| 274 | + */ | |
| 275 | + public function get_top_wins( $start_date, $end_date ) { | |
| 276 | + | |
| 277 | + /** | |
| 278 | + * Filter top wins bullets shown in the weekly email. | |
| 279 | + * | |
| 280 | + * @param array<int, mixed> $bullets Default empty array. | |
| 281 | + * @param string $start_date Range start. | |
| 282 | + * @param string $end_date Range end. | |
| 283 | + */ | |
| 284 | + $bullets = apply_filters( 'cartflows_weekly_email_top_wins', array(), $start_date, $end_date ); | |
| 285 | + | |
| 286 | + if ( ! is_array( $bullets ) ) { | |
| 287 | + return array(); | |
| 288 | + } | |
| 289 | + | |
| 290 | + $normalised = array(); | |
| 291 | + foreach ( $bullets as $bullet ) { | |
| 292 | + if ( | |
| 293 | + is_array( $bullet ) | |
| 294 | + && isset( $bullet['label'], $bullet['detail'] ) | |
| 295 | + && is_string( $bullet['label'] ) | |
| 296 | + && is_string( $bullet['detail'] ) | |
| 297 | + ) { | |
| 298 | + $normalised[] = array( | |
| 299 | + 'label' => $bullet['label'], | |
| 300 | + 'detail' => $bullet['detail'], | |
| 301 | + ); | |
| 302 | + } | |
| 303 | + } | |
| 304 | + | |
| 305 | + return $normalised; | |
| 306 | + } | |
| 307 | + | |
| 308 | + /** | |
| 309 | + * Get quick link destinations for the report email. | |
| 310 | + * | |
| 311 | + * @since 3.1.2 | |
| 312 | + * @return array<string, string> | |
| 313 | + */ | |
| 314 | + public function get_quick_links() { | |
| 315 | + | |
| 316 | + $links = array( | |
| 317 | + __( 'View full report', 'cartflows' ) => admin_url( 'admin.php?page=cartflows' ), | |
| 318 | + __( 'Edit your flows', 'cartflows' ) => admin_url( 'admin.php?page=cartflows&path=flows' ), | |
| 319 | + __( 'Browse templates', 'cartflows' ) => admin_url( 'admin.php?page=cartflows&path=library' ), | |
| 320 | + __( 'Get help', 'cartflows' ) => 'https://cartflows.com/docs/', | |
| 321 | + ); | |
| 322 | + | |
| 323 | + if ( ! _is_cartflows_pro() ) { | |
| 324 | + $links[ __( 'Try CartFlows Pro', 'cartflows' ) ] = 'https://cartflows.com/pricing/?utm_source=newsletter&utm_medium=weekly-report-email&utm_campaign=cartflows-pro'; | |
| 325 | + } else { | |
| 326 | + $links[ __( 'Discover More Products', 'cartflows' ) ] = 'https://cartflows.com/products-to-scale-growth/?utm_source=newsletter&utm_medium=weekly-report-email&utm_campaign=cartflows-bsf'; | |
| 327 | + } | |
| 328 | + | |
| 329 | + /** | |
| 330 | + * Filter the quick links shown in the weekly email. | |
| 331 | + * | |
| 332 | + * @param array<string, mixed> $links Map of label => URL. | |
| 333 | + */ | |
| 334 | + $filtered = apply_filters( 'cartflows_weekly_email_quick_links', $links ); | |
| 335 | + | |
| 336 | + if ( ! is_array( $filtered ) ) { | |
| 337 | + return $links; | |
| 338 | + } | |
| 339 | + | |
| 340 | + $normalised = array(); | |
| 341 | + foreach ( $filtered as $label => $url ) { | |
| 342 | + if ( is_string( $label ) && is_string( $url ) ) { | |
| 343 | + $normalised[ $label ] = $url; | |
| 344 | + } | |
| 345 | + } | |
| 346 | + | |
| 347 | + return $normalised; | |
| 348 | + } | |
| 349 | + | |
| 350 | + /** | |
| 183 | 351 | * Get admin report email content. |
| 184 | 352 | * |
| 185 | 353 | * @param array $stats reports details. |
| 186 | 354 | * @param string $user_name user name. |
| @@ -213,8 +381,19 @@ | ||
| 213 | 381 | $total_revenue = $stats['total_revenue']; |
| 214 | 382 | $last_month_stats = $this->get_last_month_stats(); |
| 215 | 383 | $last_month_revenue = $last_month_stats['total_revenue']; |
| 216 | 384 | $store_name = get_bloginfo( 'name' ); |
| 385 | + | |
| 386 | + $is_pro = _is_cartflows_pro(); | |
| 387 | + $start_date = gmdate( 'Y-m-d', strtotime( '-7 days' ) ); | |
| 388 | + $end_date = gmdate( 'Y-m-d' ); | |
| 389 | + $top_wins = $this->get_top_wins( $start_date, $end_date ); | |
| 390 | + $weekly_tip = $this->get_weekly_tip( $stats ); | |
| 391 | + $quick_links = $this->get_quick_links(); | |
| 392 | + $sign_off = __( 'The CartFlows team', 'cartflows' ); | |
| 393 | + | |
| 394 | + /* translators: 1: total orders, 2: total visits. */ | |
| 395 | + $preheader = sprintf( esc_html__( '%1$s orders from %2$s visits — here\'s what to optimize next.', 'cartflows' ), (int) $total_orders, (int) $total_visits ); | |
| 217 | 396 | |
| 218 | 397 | return include CARTFLOWS_DIR . 'modules/email-report/templates/email-body.php'; |
| 219 | 398 | } |
| 220 | 399 | } |