PluginProbe
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell / 3.12.12
WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell v3.12.12
3.13.3 3.13.2 3.13.1 3.13.0 3.12.13 3.12.12 3.12.11 3.12.10 3.12.9 3.12.8 3.12.7 3.12.6 3.12.5 3.12.4 3.12.3 3.12.1 3.12.2 3.12.0 3.11.1 3.11.0 3.10.9 3.10.8 3.10.7 3.10.6 2.8.16 All 261 releases
wpfunnels / admin / modules / store-checkout / views / store-checkout-listing.php

store-checkout-listing.php in WPFunnels – Funnel Builder for WooCommerce with Checkout & One Click Upsell 3.12.12, at admin/modules/store-checkout/views/store-checkout-listing.php

1,212 lines 68.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Store Checkout Listing view
4 *
5 * Shows all store checkout funnels in a list styled to match the funnel listing.
6 *
7 * @package WPFunnels
8 * @since 3.6.0
9 */
10
11 use WPFunnels\Wpfnl_functions;
12 use WPFunnels\WooCommerce\Wpfnl_Store_Checkout_Conditions;
13
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 if ( ! class_exists( 'WPFunnels\\WooCommerce\\Wpfnl_Store_Checkout_Conditions' ) ) {
19 require_once WPFNL_DIR . 'includes/core/woocommerce/class-wpfnl-store-checkout-conditions.php';
20 }
21
22 $is_pro_active = apply_filters( 'wpfunnels/is_pro_license_activated', false );
23
24 // Determine if we are viewing trash or live
25 $sc_view = isset( $_GET['sc_status'] ) && 'trash' === sanitize_text_field( $_GET['sc_status'] ) ? 'trash' : 'live';
26
27 // Live store checkout funnels
28 $all_live_funnels = Wpfnl_Store_Checkout_Conditions::get_all_store_checkout_funnels();
29 $total_live = count( $all_live_funnels );
30
31 // Trash store checkout funnels
32 $all_trash_funnels = get_posts( array(
33 'post_type' => WPFNL_FUNNELS_POST_TYPE,
34 'posts_per_page' => -1,
35 'post_status' => array( 'trash' ),
36 'orderby' => 'date',
37 'order' => 'DESC',
38 'meta_query' => array(
39 array(
40 'key' => '_wpfnl_funnel_type',
41 'value' => 'store_checkout',
42 ),
43 ),
44 ) );
45 $total_trash = count( $all_trash_funnels );
46
47 $all_funnels = 'trash' === $sc_view ? $all_trash_funnels : $all_live_funnels;
48 $total_funnels = count( $all_funnels );
49
50 // --- Store Checkout Analytics ---
51 $sc_analytics = array(
52 'total_orders' => 0,
53 'total_revenue' => 0,
54 'aov' => 0,
55 'orderbump_revenue' => 0,
56 );
57
58 if ( $total_live > 0 ) {
59 global $wpdb;
60 $stats_table = $wpdb->prefix . 'wpfnl_stats';
61 $table_exists = $wpdb->get_var( $wpdb->prepare( "SHOW TABLES LIKE %s", $stats_table ) );
62
63 if ( $table_exists ) {
64 $live_ids = wp_list_pluck( $all_live_funnels, 'ID' );
65 $placeholders = implode( ',', array_fill( 0, count( $live_ids ), '%d' ) );
66
67 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
68 $row = $wpdb->get_row( $wpdb->prepare(
69 "SELECT
70 COUNT(DISTINCT id) AS total_orders,
71 COALESCE(SUM(total_sales), 0) AS total_revenue,
72 COALESCE(SUM(orderbump_sales), 0) AS orderbump_revenue
73 FROM {$stats_table}
74 WHERE funnel_id IN ({$placeholders}) AND status IN (%s, %s)",
75 array_merge( $live_ids, array( 'completed', 'processing' ) )
76 ) );
77
78 if ( $row ) {
79 $sc_analytics['total_orders'] = (int) $row->total_orders;
80 $sc_analytics['total_revenue'] = (float) $row->total_revenue;
81 $sc_analytics['aov'] = $sc_analytics['total_orders'] > 0
82 ? round( $sc_analytics['total_revenue'] / $sc_analytics['total_orders'], 2 )
83 : 0;
84 $sc_analytics['orderbump_revenue'] = (float) $row->orderbump_revenue;
85 }
86 }
87 }
88
89 // Pagination
90 $per_page = isset( $_GET['per_page'] ) ? max( 10, (int) sanitize_text_field( $_GET['per_page'] ) ) : 10;
91 $paged = isset( $_GET['pageno'] ) ? max( 1, (int) sanitize_text_field( $_GET['pageno'] ) ) : 1;
92 $offset = ( $paged - 1 ) * $per_page;
93 $funnels = array_slice( $all_funnels, $offset, $per_page );
94 $total_pages = $per_page > 0 ? (int) ceil( $total_funnels / $per_page ) : 1;
95
96 $sc_listing_url = admin_url( 'admin.php?page=store_checkout' );
97 $sc_trash_url = admin_url( 'admin.php?page=store_checkout&sc_status=trash' );
98
99 $condition_labels = array(
100 'all' => __( 'No Condition', 'wpfnl' ),
101 'products' => __( 'Specific Products', 'wpfnl' ),
102 'categories' => __( 'Product Categories', 'wpfnl' ),
103 'tags' => __( 'Product Tags', 'wpfnl' ),
104 'date_range' => __( 'Date Range', 'wpfnl' ),
105 'rules' => __( 'Custom Rules', 'wpfnl' ),
106 );
107
108 /**
109 * Build tooltip text for a single rule by resolving its value IDs to names.
110 */
111 function wpfnl_sc_rule_tooltip( $rule, $condition_labels, $total_rules = 1 ) {
112 $rtype = isset( $rule['type'] ) ? $rule['type'] : 'all';
113 $values = isset( $rule['values'] ) ? (array) $rule['values'] : array();
114 $or_note = $total_rules > 1 ? ' ' . __( '(OR with other rules)', 'wpfnl' ) : '';
115
116 if ( empty( $values ) ) {
117 return __( 'This checkout will appear when the condition is met.', 'wpfnl' ) . $or_note;
118 }
119
120 $names = array();
121 foreach ( $values as $val_id ) {
122 $val_id = (int) $val_id;
123 if ( 'products' === $rtype ) {
124 $names[] = get_the_title( $val_id );
125 } elseif ( 'categories' === $rtype ) {
126 $term = get_term( $val_id, 'product_cat' );
127 $names[] = ( $term && ! is_wp_error( $term ) ) ? $term->name : '#' . $val_id;
128 } elseif ( 'tags' === $rtype ) {
129 $term = get_term( $val_id, 'product_tag' );
130 $names[] = ( $term && ! is_wp_error( $term ) ) ? $term->name : '#' . $val_id;
131 }
132 }
133
134 $names_str = implode( ', ', $names );
135
136 switch ( $rtype ) {
137 case 'products':
138 /* translators: %s = comma-separated product names */
139 return sprintf( __( 'This checkout will appear when the cart contains: %s.', 'wpfnl' ), $names_str ) . $or_note;
140 case 'categories':
141 /* translators: %s = comma-separated category names */
142 return sprintf( __( 'This checkout will appear when the cart has products from: %s.', 'wpfnl' ), $names_str ) . $or_note;
143 case 'tags':
144 /* translators: %s = comma-separated tag names */
145 return sprintf( __( 'This checkout will appear when the cart has products tagged: %s.', 'wpfnl' ), $names_str ) . $or_note;
146 default:
147 return __( 'This checkout will appear when the condition is met.', 'wpfnl' ) . $or_note;
148 }
149 }
150
151 ?>
152
153 <div class="wpfnl wpfnl-store-checkout-listing-page">
154 <div class="wpfnl-dashboard">
155 <nav class="wpfnl-dashboard__nav">
156 <?php require_once WPFNL_DIR . '/admin/partials/dashboard-nav.php'; ?>
157
158 <?php if ( ! $is_pro_active ) : ?>
159 <div class="wpfnl-dashboard__nav-right">
160 <a href="https://getwpfunnels.com/pricing/" class="btn-default" target="_blank"
161 title="<?php esc_attr_e( 'Upgrade to Pro', 'wpfnl' ); ?>"
162 aria-label="<?php esc_attr_e( 'Upgrade to Pro', 'wpfnl' ); ?>">
163 <?php esc_html_e( 'Upgrade to Pro', 'wpfnl' ); ?>
164 </a>
165 </div>
166 <?php endif; ?>
167 </nav>
168
169 <div class="dashboard-nav__content">
170
171 <div id="templates-library"></div>
172
173 <?php
174 $sc_count_active = Wpfnl_functions::count_store_checkout_funnels();
175 $sc_limit_reached = ! $is_pro_active && $sc_count_active >= 3;
176 ?>
177
178 <!-- Page header (matches funnel-listing header style) -->
179 <div class="wpfnl-dashboard__header overview-header">
180 <div class="wpfnl-dashboard-header-left">
181 <!-- <div class="wpfnl-dashboard-links-wrapper">
182 <a href="<?php echo esc_url( $sc_listing_url ); ?>" class="wpfnl-all-funnels <?php echo 'live' === $sc_view ? 'active' : ''; ?>">
183 <span><?php esc_html_e( 'Live', 'wpfnl' ); ?></span>
184 <span class="wpfnl-count"><?php echo esc_html( $total_live ); ?></span>
185 </a>
186 <a href="<?php echo esc_url( $sc_trash_url ); ?>" class="wpfnl-trash-all-funnels <?php echo 'trash' === $sc_view ? 'active' : ''; ?>">
187 <span><?php esc_html_e( 'Trash', 'wpfnl' ); ?></span>
188 <span class="wpfnl-count"><?php echo esc_html( $total_trash ); ?></span>
189 </a>
190 </div> -->
191 </div>
192 <?php if ( 'live' === $sc_view && ( $total_live || $total_funnels ) ) : ?>
193 <?php
194 $sc_btn_classes = 'btn-default add-new-funnel-btn';
195 if ( $sc_limit_reached ) {
196 $sc_btn_classes .= ' disabled';
197 }
198 ?>
199 <a href="#" id="wpfnl-create-store-checkout" class="<?php echo esc_attr( $sc_btn_classes ); ?>">
200 <?php
201 if ( $sc_limit_reached ) {
202 require WPFNL_DIR . '/admin/partials/icons/lock-icon.php';
203 } else {
204 require WPFNL_DIR . '/admin/partials/icons/plus-icon.php';
205 }
206 esc_html_e( 'Store Checkout', 'wpfnl' );
207 ?>
208 </a>
209 <?php endif; ?>
210
211 </div><!-- /.wpfnl-dashboard__header -->
212
213 <?php if ( $sc_limit_reached ) : ?>
214 <div class="upgrade-to-pro">
215 <div class="upgrade-to-pro-wrapper">
216 <div class="warning-icon-wrapper">
217 <span class="warning-icon">
218 <?php require WPFNL_DIR . '/admin/partials/icons/warning-icon.php'; ?>
219 </span>
220 </div>
221 <div class="upgrade-to-pro-content">
222 <div class="upgrade-to-pro-message">
223 <h3><?php esc_html_e( 'You have hit the limit! Upgrade to Pro for unlimited store checkouts!', 'wpfnl' ); ?></h3>
224 <p><?php esc_html_e( 'You are using the free version of WPFunnels which allows you to create up to 3 store checkouts. To build more store checkouts, either move one to trash or Upgrade to Pro.', 'wpfnl' ); ?></p>
225 </div>
226 </div>
227 <div class="upgrade-to-pro-action">
228 <a href="https://getwpfunnels.com/pricing/" target="_blank" class="btn-upgrade-to-pro"><?php esc_html_e( 'Upgrade to Pro', 'wpfnl' ); ?></a>
229 </div>
230 </div>
231 </div>
232 <?php endif; ?>
233
234 <?php if ( 'live' === $sc_view ) : ?>
235 <!-- Store Checkout Analytics Overview -->
236 <div class="wpfnl-sc-analytics-overview">
237 <div class="wpfnl-sc-analytics-cards">
238 <div class="wpfnl-sc-analytics-card">
239 <div class="wpfnl-sc-analytics-card__icon">
240 <span class="icon-wrap icon-wrap--purple">
241 <svg width="20" height="21" fill="none" viewBox="0 0 20 21" xmlns="http://www.w3.org/2000/svg"><g fill="#6E42D3" clip-path="url(#clip_sc_gs)"><path d="M6.66 4.279h6.68l1.442-1.15c.491-.39.674-1.024.467-1.615A1.438 1.438 0 0013.876.54h-7.75a1.44 1.44 0 00-1.374.973 1.433 1.433 0 00.466 1.614l1.443 1.15zm6.794 1.245H6.546C4.27 7.751 2.5 11.658 2.5 14.868c0 2.79 1.482 5.607 4.792 5.607h5.625c2.827 0 4.583-2.149 4.583-5.607 0-3.21-1.77-7.117-4.046-9.344zm-3.77 6.853h.633c.974 0 1.766.79 1.766 1.76 0 .873-.631 1.592-1.458 1.738v.654a.624.624 0 01-1.25 0v-.622h-.833a.624.624 0 01-.625-.623c0-.344.28-.623.625-.623h1.775a.516.516 0 00.516-.515.518.518 0 00-.516-.524h-.634c-.974 0-1.766-.79-1.766-1.76 0-.873.631-1.592 1.458-1.738V9.47a.624.624 0 011.25 0v.622h.833a.624.624 0 110 1.246H9.683a.516.516 0 00-.516.515c0 .293.231.524.516.524z"/></g><defs><clipPath id="clip_sc_gs"><path fill="#fff" d="M0 0h20v19.934H0z" transform="translate(0 .54)"/></clipPath></defs></svg>
242 </span>
243 </div>
244 <div class="wpfnl-sc-analytics-card__content">
245 <span class="card-title"><?php esc_html_e( 'Total Orders', 'wpfnl' ); ?></span>
246 <span class="card-value"><?php echo esc_html( number_format_i18n( $sc_analytics['total_orders'] ) ); ?></span>
247 </div>
248 </div>
249
250 <div class="wpfnl-sc-analytics-card">
251 <div class="wpfnl-sc-analytics-card__icon">
252 <span class="icon-wrap icon-wrap--orange">
253 <svg width="18" height="21" fill="none" viewBox="0 0 18 21" xmlns="http://www.w3.org/2000/svg"><path fill="#EE8134" d="M6.023 20.488a1.253 1.253 0 01-.885-.361 1.244 1.244 0 01.875-2.13h.01a1.243 1.243 0 110 2.492zm9.254-1.246c0-.33-.131-.647-.366-.88a1.253 1.253 0 00-.884-.366h-.01a1.253 1.253 0 00-1.149.776 1.241 1.241 0 00.278 1.355 1.252 1.252 0 002.131-.885zm2.69-12.598l-1.01 6.16a2.564 2.564 0 01-.926 1.882 2.583 2.583 0 01-2.025.57H5.732a2 2 0 01-1.313-.488 1.985 1.985 0 01-.667-1.227L2.25 3.128a1.238 1.238 0 00-1.24-1.079H.75A.752.752 0 010 1.302.746.746 0 01.75.554h.26a2.736 2.736 0 011.808.666c.501.434.827 1.035.916 1.69l.209 1.382h12.063a2.007 2.007 0 011.532.72 1.99 1.99 0 01.43 1.632zm-5.455 1.272a.75.75 0 00-1.061 0l-2.137 2.129-.8-.798a.752.752 0 00-1.272.53.746.746 0 00.21.527l1.334 1.33a.754.754 0 001.061 0l2.665-2.658a.747.747 0 000-1.06z"/></svg>
254 </span>
255 </div>
256 <div class="wpfnl-sc-analytics-card__content">
257 <span class="card-title"><?php esc_html_e( 'Total Revenue', 'wpfnl' ); ?></span>
258 <span class="card-value"><?php echo function_exists( 'wc_price' ) ? wp_kses_post( wc_price( $sc_analytics['total_revenue'] ) ) : esc_html( $sc_analytics['total_revenue'] ); ?></span>
259 </div>
260 </div>
261
262 <div class="wpfnl-sc-analytics-card">
263 <div class="wpfnl-sc-analytics-card__icon">
264 <span class="icon-wrap icon-wrap--blue">
265 <svg width="20" height="21" fill="none" viewBox="0 0 20 21" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="13.54" width="4" height="7" rx="1" fill="#2E90FA"/><rect x="8" y="8.54" width="4" height="12" rx="1" fill="#2E90FA"/><rect x="14" y="3.54" width="4" height="17" rx="1" fill="#2E90FA"/></svg>
266 </span>
267 </div>
268 <div class="wpfnl-sc-analytics-card__content">
269 <span class="card-title"><?php esc_html_e( 'Avg. Order Value', 'wpfnl' ); ?></span>
270 <span class="card-value"><?php echo function_exists( 'wc_price' ) ? wp_kses_post( wc_price( $sc_analytics['aov'] ) ) : esc_html( $sc_analytics['aov'] ); ?></span>
271 </div>
272 </div>
273
274 <div class="wpfnl-sc-analytics-card">
275 <div class="wpfnl-sc-analytics-card__icon">
276 <span class="icon-wrap icon-wrap--green">
277 <svg width="18" height="21" fill="none" viewBox="0 0 18 21" xmlns="http://www.w3.org/2000/svg"><path fill="#12B76A" d="M7.576.554a.678.678 0 00-.69.668c0 1.116-.403 1.77-.924 2.607-.286.458-.742 1.215-.938 1.796-.205-.396-.322-.69-.504-1.324-.148-.528-.859-.669-1.212-.24C.711 7.167-.052 9.498.003 11.855c.11 4.748 4.037 8.632 9 8.632 4.961 0 8.997-3.879 8.997-8.646 0-1.225-.295-2.815-.905-4.31-.61-1.495-1.529-2.915-2.938-3.639-.397-.202-.888.008-.996.428a9.852 9.852 0 01-.347 1.15 7.633 7.633 0 00-1.037-2.496C10.905 1.63 9.467.555 7.576.555zm-.888 8.793c.573 0 1.038.447 1.038.998 0 .55-.465.997-1.038.997s-1.039-.447-1.039-.997.466-.998 1.039-.998zm4.912.007a.634.634 0 01.514.16c.286.242.316.66.066.937L6.86 16.27a.712.712 0 01-.975.064.647.647 0 01-.061-.941l5.314-5.819c.106-.117.28-.2.462-.22zm-.288 5.148c.573 0 1.039.446 1.039.997 0 .55-.466.998-1.039.998s-1.038-.447-1.038-.998c0-.55.464-.997 1.038-.997z"/></svg>
278 </span>
279 </div>
280 <div class="wpfnl-sc-analytics-card__content">
281 <span class="card-title"><?php esc_html_e( 'Bump Offer Revenue', 'wpfnl' ); ?></span>
282 <span class="card-value"><?php echo function_exists( 'wc_price' ) ? wp_kses_post( wc_price( $sc_analytics['orderbump_revenue'] ) ) : esc_html( $sc_analytics['orderbump_revenue'] ); ?></span>
283 </div>
284 </div>
285 </div>
286
287 <!-- <div class="wpfnl-sc-analytics-toggle">
288 <span class="wpfnl-sc-analytics-toggle__btn" id="wpfnl-sc-analytics-toggle">
289 <svg class="toggle-arrow" width="14" height="8" fill="none" viewBox="0 0 14 8" xmlns="http://www.w3.org/2000/svg"><path d="M1 1l6 6 6-6" stroke="#7A8B9A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
290 </span>
291 </div> -->
292 </div>
293 <?php endif; ?>
294
295 <!-- Funnel-style listing -->
296 <div class="wpfnl-dashboard__inner-content <?php echo $total_funnels ? '' : 'no-funnel'; ?>">
297 <div class="funnel-list__wrapper">
298
299 <?php if ( $total_funnels ) : ?>
300
301 <!-- Header row -->
302 <div class="funnel__single-list list-header">
303 <div class="bulk-action-wrapper">
304 <p>
305 <span class="selected-funnel-count">0 <?php esc_html_e( 'Store Checkout', 'wpfnl' ); ?></span>
306 <?php esc_html_e( 'Selected', 'wpfnl' ); ?>
307 </p>
308 <button class="btn-default bulk-delete-toggler">
309 <?php esc_html_e( 'Bulk Actions', 'wpfnl' ); ?>
310 <svg width="8" height="6" fill="none" viewBox="0 0 8 6" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" stroke="#fff" stroke-width=".2" d="M4 5.28a.559.559 0 01-.396-.164l-3.44-3.44A.56.56 0 11.956.884L4 3.928 7.044.884a.56.56 0 01.792.792l-3.44 3.44A.559.559 0 014 5.28z"/></svg>
311 <ul class="wpfnl-dropdown">
312 <?php if ( 'trash' === $sc_view ) : ?>
313 <li>
314 <a href="#" class="delete wpfnl-sc-bulk-restore" title="<?php esc_attr_e( 'Restore Selected', 'wpfnl' ); ?>">
315 <?php require WPFNL_DIR . '/admin/partials/icons/restore-icon.php'; ?>
316 <?php esc_html_e( 'Restore', 'wpfnl' ); ?>
317 </a>
318 </li>
319 <li>
320 <a href="#" class="delete wpfnl-sc-bulk-delete" title="<?php esc_attr_e( 'Delete Permanently', 'wpfnl' ); ?>">
321 <?php require WPFNL_DIR . '/admin/partials/icons/delete-icon.php'; ?>
322 <?php esc_html_e( 'Delete', 'wpfnl' ); ?>
323 </a>
324 </li>
325 <?php else : ?>
326 <li>
327 <a href="#" class="delete wpfnl-sc-bulk-trash" title="<?php esc_attr_e( 'Trash Selected', 'wpfnl' ); ?>">
328 <?php require WPFNL_DIR . '/admin/partials/icons/trash-icon.php'; ?>
329 <?php esc_html_e( 'Trash', 'wpfnl' ); ?>
330 </a>
331 </li>
332 <?php endif; ?>
333 </ul>
334 </button>
335 </div>
336
337 <div class="funnel-list__bulk-action">
338 <div class="funnel-list__bulk-select select-all-funnels">
339 <span class="wpfnl-checkbox no-title">
340 <input type="checkbox" name="wpfnl-sc-bulk-select" id="wpfnl-sc-bulk-select">
341 <label for="wpfnl-sc-bulk-select"></label>
342 </span>
343 </div>
344 </div>
345
346 <div class="list-cell wpfnl-name"><?php esc_html_e( 'Name', 'wpfnl' ); ?></div>
347 <div class="list-cell wpfnl-sc-priority"><?php esc_html_e( 'Priority', 'wpfnl' ); ?></div>
348 <div class="list-cell wpfnl-creation-date"><?php esc_html_e( 'Creation Date', 'wpfnl' ); ?></div>
349 <div class="list-cell wpfnl-status"><?php esc_html_e( 'Status', 'wpfnl' ); ?></div>
350 <div class="list-cell list-action"><?php esc_html_e( 'Action', 'wpfnl' ); ?></div>
351 </div>
352
353 <?php
354 // Pre-compute priority for all funnels.
355 // Conditional (published) funnels first (newest = #1), then catch-all.
356 $priority_map = array();
357 $conditional_ids = array();
358 $catchall_ids = array();
359
360 foreach ( $all_funnels as $_f ) {
361 $_sid = Wpfnl_Store_Checkout_Conditions::get_checkout_step_id_for_funnel( $_f->ID );
362 $_cond = $_sid ? Wpfnl_Store_Checkout_Conditions::get_condition( $_sid ) : array( 'condition_type' => 'all' );
363 if ( Wpfnl_Store_Checkout_Conditions::is_catch_all( $_cond ) ) {
364 $catchall_ids[] = $_f->ID;
365 } else {
366 $conditional_ids[] = $_f->ID;
367 }
368 }
369
370 // $all_funnels is already newest-first (DESC) from the query.
371 $pri = 1;
372 foreach ( $conditional_ids as $_fid ) {
373 $priority_map[ $_fid ] = $pri++;
374 }
375 // Among catch-all funnels, only the first (newest) acts as true fallback.
376 $first_catchall = true;
377 $catchall_overridden = array();
378 foreach ( $catchall_ids as $_fid ) {
379 $priority_map[ $_fid ] = $pri++;
380 if ( $first_catchall ) {
381 $first_catchall = false;
382 } else {
383 $catchall_overridden[ $_fid ] = true;
384 }
385 }
386 ?>
387
388 <?php foreach ( $funnels as $funnel ) :
389 $funnel_id = $funnel->ID;
390 $step_id = Wpfnl_Store_Checkout_Conditions::get_checkout_step_id_for_funnel( $funnel_id );
391
392 // Edit URL
393 $edit_url = add_query_arg(
394 array(
395 'page' => WPFNL_EDIT_FUNNEL_SLUG,
396 'id' => $funnel_id,
397 'step_id' => 0,
398 ),
399 admin_url( 'admin.php' )
400 );
401
402 // View URL (checkout step permalink)
403 $view_url = '#';
404 if ( $step_id ) {
405 $permalink = get_the_permalink( $step_id );
406 if ( $permalink ) {
407 $view_url = $permalink;
408 }
409 }
410
411 // Build per-rule condition badges
412 $condition = $step_id
413 ? Wpfnl_Store_Checkout_Conditions::get_condition( $step_id )
414 : array( 'condition_type' => 'all' );
415 $cond_type = isset( $condition['condition_type'] ) ? $condition['condition_type'] : 'all';
416
417 $cond_badges = array(); // each entry: array( 'label' => '…', 'active' => bool, 'tooltip' => '…', 'is_date' => bool )
418 $rules_count = 0;
419 if ( 'rules' === $cond_type ) {
420 $rules = isset( $condition['rules'] ) && is_array( $condition['rules'] ) ? $condition['rules'] : array();
421 $rules_count = count( $rules );
422 foreach ( $rules as $rule ) {
423 $rtype = isset( $rule['type'] ) ? $rule['type'] : 'all';
424 $label = isset( $condition_labels[ $rtype ] ) ? $condition_labels[ $rtype ] : $condition_labels['all'];
425 $cond_badges[] = array(
426 'label' => $label,
427 'active' => ( $label !== $condition_labels['all'] ),
428 'tooltip' => wpfnl_sc_rule_tooltip( $rule, $condition_labels, $rules_count ),
429 'is_date' => false,
430 );
431 }
432 }
433
434 // Check for date range
435 $use_date = ! empty( $condition['use_date_range'] );
436 if ( $use_date ) {
437 $d_from = isset( $condition['date_from'] ) ? $condition['date_from'] : '';
438 $d_to = isset( $condition['date_to'] ) ? $condition['date_to'] : '';
439 $has_rules = $rules_count > 0;
440 if ( $d_from && $d_to ) {
441 if ( $has_rules ) {
442 $date_tip = sprintf( __( 'Additionally, this checkout will only be active between %1$s and %2$s.', 'wpfnl' ), $d_from, $d_to );
443 } else {
444 $date_tip = sprintf( __( 'This checkout will only be active between %1$s and %2$s.', 'wpfnl' ), $d_from, $d_to );
445 }
446 } elseif ( $d_from ) {
447 if ( $has_rules ) {
448 $date_tip = sprintf( __( 'Additionally, this checkout will only be active from %s onwards.', 'wpfnl' ), $d_from );
449 } else {
450 $date_tip = sprintf( __( 'This checkout will only be active from %s onwards.', 'wpfnl' ), $d_from );
451 }
452 } elseif ( $d_to ) {
453 if ( $has_rules ) {
454 $date_tip = sprintf( __( 'Additionally, this checkout will only be active until %s.', 'wpfnl' ), $d_to );
455 } else {
456 $date_tip = sprintf( __( 'This checkout will only be active until %s.', 'wpfnl' ), $d_to );
457 }
458 } else {
459 $date_tip = __( 'This checkout has a date range condition.', 'wpfnl' );
460 }
461 $cond_badges[] = array(
462 'label' => $condition_labels['date_range'],
463 'active' => true,
464 'tooltip' => $date_tip,
465 'is_date' => true,
466 );
467 }
468
469 // Fallback: no rules at all
470 $is_catch_all = empty( $cond_badges );
471 if ( $is_catch_all ) {
472 $cond_badges[] = array(
473 'label' => $condition_labels['all'],
474 'active' => false,
475 'tooltip' => __( 'This store checkout will apply as the default WooCommerce checkout without any condition.', 'wpfnl' ),
476 );
477 }
478
479 // Builder icon
480 $builder = Wpfnl_functions::get_page_builder_by_step_id( $funnel_id );
481
482 // Status
483 $status_class = ( 'publish' === $funnel->post_status ) ? 'enabled' : $funnel->post_status;
484 $status_label = ( 'publish' === $funnel->post_status ) ? __( 'Enabled', 'wpfnl' ) : __( 'Disabled', 'wpfnl' );
485 $toggle_status = ( 'publish' === $funnel->post_status ) ? 'draft' : 'publish';
486 $toggle_label = ( 'publish' === $funnel->post_status ) ? __( 'Disable', 'wpfnl' ) : __( 'Enable', 'wpfnl' );
487
488 // Creation date
489 $creation_date = get_the_date( 'Y-m-d g:i A', $funnel_id );
490 ?>
491
492 <div class="funnel__single-list list-body">
493
494 <div class="funnel-list__bulk-action">
495 <span class="wpfnl-checkbox no-title">
496 <input type="checkbox" name="wpfnl-sc-list-select" id="wpfnl-sc-list<?php echo esc_attr( $funnel_id ); ?>-select" data-id="<?php echo esc_attr( $funnel_id ); ?>">
497 <label for="wpfnl-sc-list<?php echo esc_attr( $funnel_id ); ?>-select"></label>
498 </span>
499 </div>
500
501 <div class="list-cell wpfnl-name wpfnl-sc-name-cell">
502 <?php if ( $builder ) : ?>
503 <span class="builder-logo" title="<?php echo esc_attr( str_replace( '-', ' ', ucfirst( $builder ) ) ); ?>">
504 <?php include WPFNL_DIR . '/admin/partials/icons/' . $builder . '.php'; ?>
505 </span>
506 <?php else : ?>
507 <span class="builder-logo" title="<?php esc_attr_e( 'No Builder Found', 'wpfnl' ); ?>"></span>
508 <?php endif; ?>
509 <div class="wpfnl-sc-name-inner">
510 <a href="<?php echo esc_url( $edit_url ); ?>" class="name">
511 <?php echo esc_html( get_the_title( $funnel_id ) ); ?>
512 </a>
513 <?php
514 // Build a flat text summary for the single-line display
515 $badge_texts = array();
516 foreach ( $cond_badges as $idx => $badge ) {
517 if ( $idx > 0 ) {
518 $badge_texts[] = ! empty( $badge['is_date'] ) ? 'AND' : 'OR';
519 }
520 $badge_texts[] = $badge['label'];
521 }
522 $condition_summary = implode( ' ', $badge_texts );
523
524 // Build full tooltip with all rules explained
525 $tooltip_parts = array();
526 foreach ( $cond_badges as $badge ) {
527 $tooltip_parts[] = $badge['tooltip'];
528 }
529 $full_tooltip = implode( ' ', $tooltip_parts );
530 ?>
531 <span class="sc-condition-line <?php echo $is_catch_all ? 'sc-condition-line--inactive' : 'sc-condition-line--active'; ?>">
532 <span class="sc-condition-line__text"><?php echo esc_html( $condition_summary ); ?></span>
533 <span class="sc-condition-line__tooltip"><?php echo esc_html( $full_tooltip ); ?></span>
534 </span>
535 </div>
536 </div>
537
538 <div class="list-cell wpfnl-sc-priority">
539 <?php
540 $pri_num = isset( $priority_map[ $funnel_id ] ) ? $priority_map[ $funnel_id ] : '-';
541 $is_overridden = isset( $catchall_overridden[ $funnel_id ] );
542
543 if ( $is_overridden ) {
544 $pri_text = __( 'Overridden', 'wpfnl' );
545 $pri_class = 'sc-priority-badge--overridden';
546 $pri_tip = __( 'This fallback checkout is overridden by a newer fallback. Only the most recently created fallback is active when no conditional checkout matches.', 'wpfnl' );
547 } elseif ( $is_catch_all ) {
548 $pri_text = __( 'Default', 'wpfnl' );
549 $pri_class = 'sc-priority-badge--fallback';
550 $pri_tip = __( 'This checkout has no condition and acts as the default fallback. It will only be used when no other conditional store checkout matches the customer\'s cart.', 'wpfnl' );
551 } elseif ( 1 === $pri_num ) {
552 $pri_text = __( 'Highest', 'wpfnl' );
553 $pri_class = 'sc-priority-badge--active';
554 $pri_tip = __( 'This is the most recently created conditional checkout. It will be evaluated first and takes priority over all other store checkouts.', 'wpfnl' );
555 } else {
556 /* translators: %d = priority position number */
557 $pri_text = sprintf( __( '#%d', 'wpfnl' ), $pri_num );
558 $pri_class = 'sc-priority-badge--active';
559 /* translators: %d = priority position number */
560 $pri_tip = sprintf( __( 'This checkout has evaluation priority #%d. Store checkouts with conditions are evaluated from newest to oldest. The first match wins.', 'wpfnl' ), $pri_num );
561 }
562 ?>
563 <span class="sc-priority-badge <?php echo esc_attr( $pri_class ); ?>">
564 <?php echo esc_html( $pri_text ); ?>
565 <span class="sc-priority-badge__tooltip"><?php echo esc_html( $pri_tip ); ?></span>
566 </span>
567 </div>
568
569 <div class="list-cell wpfnl-creation-date">
570 <span class="post-date"><?php echo esc_html( $creation_date ); ?></span>
571 </div>
572
573 <div class="list-cell wpfnl-status <?php echo esc_attr( $status_class ); ?>">
574 <span class="post-status"><?php echo esc_html( $status_label ); ?></span>
575 </div>
576
577 <div class="list-cell list-action">
578 <?php if ( 'trash' === $sc_view ) : ?>
579 <span class="more-action funnel-list__more-action"
580 title="<?php esc_attr_e( 'More options', 'wpfnl' ); ?>">
581 <?php require WPFNL_DIR . '/admin/partials/icons/dot-icon.php'; ?>
582 <ul class="more-actions wpfnl-dropdown">
583 <li>
584 <a href="#" class="wpfnl-sc-restore-funnel"
585 data-id="<?php echo esc_attr( $funnel_id ); ?>">
586 <?php require WPFNL_DIR . '/admin/partials/icons/restore-icon.php'; ?>
587 <?php esc_html_e( 'Restore', 'wpfnl' ); ?>
588 </a>
589 </li>
590 <li>
591 <a href="#" class="delete wpfnl-sc-delete-funnel"
592 data-id="<?php echo esc_attr( $funnel_id ); ?>">
593 <?php require WPFNL_DIR . '/admin/partials/icons/delete-icon.php'; ?>
594 <?php esc_html_e( 'Delete Permanently', 'wpfnl' ); ?>
595 </a>
596 </li>
597 </ul>
598 </span>
599 <?php else : ?>
600 <a href="<?php echo esc_url( $edit_url ); ?>" class="edit"
601 title="<?php esc_attr_e( 'Edit', 'wpfnl' ); ?>">
602 <?php require WPFNL_DIR . '/admin/partials/icons/edit-icon.php'; ?>
603 </a>
604 <a href="<?php echo esc_url( $view_url ); ?>" class="view" target="_blank"
605 title="<?php esc_attr_e( 'View', 'wpfnl' ); ?>">
606 <?php require WPFNL_DIR . '/admin/partials/icons/eye-icon.php'; ?>
607 </a>
608 <span class="more-action funnel-list__more-action"
609 title="<?php esc_attr_e( 'More options', 'wpfnl' ); ?>">
610 <?php require WPFNL_DIR . '/admin/partials/icons/dot-icon.php'; ?>
611 <ul class="more-actions wpfnl-dropdown">
612 <li>
613 <a href="#" class="wpfnl-sc-status-toggle"
614 data-id="<?php echo esc_attr( $funnel_id ); ?>"
615 data-status="<?php echo esc_attr( $toggle_status ); ?>">
616 <?php if ( 'publish' === $funnel->post_status ) : ?>
617 <?php require WPFNL_DIR . '/admin/partials/icons/draft-icon.php'; ?>
618 <?php else : ?>
619 <?php require WPFNL_DIR . '/admin/partials/icons/publish-icon.php'; ?>
620 <?php endif; ?>
621 <?php echo esc_html( $toggle_label ); ?>
622 </a>
623 </li>
624 <li>
625 <a href="#" class="delete wpfnl-sc-trash-funnel"
626 data-id="<?php echo esc_attr( $funnel_id ); ?>"
627 title="<?php esc_attr_e( 'Trash', 'wpfnl' ); ?>">
628 <?php require WPFNL_DIR . '/admin/partials/icons/trash-icon.php'; ?>
629 <?php esc_html_e( 'Trash', 'wpfnl' ); ?>
630 </a>
631 </li>
632 </ul>
633 </span>
634 <?php endif; ?>
635 </div>
636
637 </div>
638
639 <?php endforeach; ?>
640
641 <!-- Pagination footer -->
642 <div class="list-footer">
643 <div class="pagination-number">
644 <p>
645 <strong><?php esc_html_e( 'Showing', 'wpfnl' ); ?></strong>
646 <select id="wpfnl-sc-per-page">
647 <?php foreach ( array( 10, 20, 30 ) as $pp ) : ?>
648 <option value="<?php echo esc_attr( $pp ); ?>" <?php selected( $per_page, $pp ); ?>>
649 <?php echo esc_html( $pp ); ?>
650 </option>
651 <?php endforeach; ?>
652 </select>
653 <?php
654 $limit_starts = $offset + 1;
655 $limit_ends = min( $offset + $per_page, $total_funnels );
656 echo esc_html( "{$limit_starts}-{$limit_ends} of {$total_funnels} " . __( 'items', 'wpfnl' ) );
657 ?>
658 </p>
659 </div>
660 <div class="pagination">
661 <div class="wpfnl-pagination">
662 <?php
663 $pag_args = array( 'page' => 'store_checkout', 'per_page' => $per_page );
664 if ( 'trash' === $sc_view ) {
665 $pag_args['sc_status'] = 'trash';
666 }
667 $prev_url = $paged <= 1 ? '#' : add_query_arg( array_merge( $pag_args, array( 'pageno' => $paged - 1 ) ), admin_url( 'admin.php' ) );
668 $next_url = $paged >= $total_pages ? '#' : add_query_arg( array_merge( $pag_args, array( 'pageno' => $paged + 1 ) ), admin_url( 'admin.php' ) );
669 ?>
670 <a href="<?php echo esc_url( $prev_url ); ?>"
671 class="nav-link prev <?php echo $paged <= 1 ? 'disabled' : ''; ?>">
672 <svg width="12" height="12" fill="none" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path fill="#7A8B9A" d="M6.002 12a.856.856 0 01-.609-.25L.25 6.586a.863.863 0 010-1.214L5.393.207a.855.855 0 011.415.62.863.863 0 01-.206.594L2.067 5.974l4.535 4.554a.862.862 0 01-.6 1.472z"/><path fill="#7A8B9A" d="M11.147 12a.856.856 0 01-.61-.25L5.395 6.586a.863.863 0 010-1.214L10.538.207a.855.855 0 011.414.62.862.862 0 01-.205.594L7.21 5.974l4.536 4.554a.862.862 0 01-.6 1.472z"/></svg>
673 </a>
674
675 <?php for ( $i = 1; $i <= $total_pages; $i++ ) : ?>
676 <a href="<?php echo esc_url( add_query_arg( array_merge( $pag_args, array( 'pageno' => $i ) ), admin_url( 'admin.php' ) ) ); ?>"
677 class="nav-link <?php echo $i === $paged ? 'active' : ''; ?>">
678 <?php echo esc_html( $i ); ?>
679 </a>
680 <?php endfor; ?>
681
682 <a href="<?php echo esc_url( $next_url ); ?>"
683 class="nav-link next <?php echo $paged >= $total_pages ? 'disabled' : ''; ?>">
684 <svg width="12" height="12" fill="none" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path fill="#7A8B9A" d="M5.998 12a.856.856 0 00.609-.25l5.144-5.164a.863.863 0 000-1.214L6.607.207a.855.855 0 00-1.415.62.863.863 0 00.206.594l4.535 4.553-4.535 4.554a.862.862 0 00.6 1.472z"/><path fill="#7A8B9A" d="M.853 12a.856.856 0 00.61-.25l5.143-5.164a.863.863 0 000-1.214L1.462.207a.855.855 0 00-1.414.62.863.863 0 00.205.594L4.79 5.974.253 10.528A.862.862 0 00.853 12z"/></svg>
685 </a>
686 </div>
687 </div>
688 </div>
689
690 <?php else : ?>
691
692 <?php if ( 'trash' === $sc_view ) : ?>
693 <!-- Trash empty state -->
694 <div class="no-trash-wrapper">
695 <?php require WPFNL_DIR . '/admin/partials/icons/no-data-icon.php'; ?>
696 <p class="no-funnel"><?php esc_html_e( 'No data Found', 'wpfnl' ); ?></p>
697 </div>
698 <?php else : ?>
699 <!-- Empty state (matches funnel-listing no-funnel-wrapper style) -->
700 <div class="no-funnel-wrapper">
701 <div class="no-funnel-info">
702 <div class="info-content">
703 <h2 class="info-title">
704 <?php esc_html_e( 'Create your first Store Checkout', 'wpfnl' ); ?>
705 </h2>
706 <p class="info-description">
707 <?php esc_html_e( 'Replace the default WooCommerce checkout with a custom checkout funnel to boost conversions.', 'wpfnl' ); ?>
708 </p>
709
710 <ul class="info-features">
711 <li class="feature-item">
712 <svg xmlns="http://www.w3.org/2000/svg" width="11" height="8" viewBox="0 0 11 8" fill="none"><path d="M10.0326 0.699951L3.61589 7.11662L0.699219 4.19995" stroke="#444d5e" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
713 <?php esc_html_e( 'Custom Checkout Pages', 'wpfnl' ); ?>
714 </li>
715 <li class="feature-item">
716 <svg xmlns="http://www.w3.org/2000/svg" width="11" height="8" viewBox="0 0 11 8" fill="none"><path d="M10.0326 0.699951L3.61589 7.11662L0.699219 4.19995" stroke="#444d5e" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
717 <?php esc_html_e( 'Order Bumps', 'wpfnl' ); ?>
718 </li>
719 <li class="feature-item">
720 <svg xmlns="http://www.w3.org/2000/svg" width="11" height="8" viewBox="0 0 11 8" fill="none"><path d="M10.0326 0.699951L3.61589 7.11662L0.699219 4.19995" stroke="#444d5e" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
721 <?php esc_html_e( 'Conditional Checkout Routing', 'wpfnl' ); ?>
722 </li>
723 <li class="feature-item">
724 <svg xmlns="http://www.w3.org/2000/svg" width="11" height="8" viewBox="0 0 11 8" fill="none"><path d="M10.0326 0.699951L3.61589 7.11662L0.699219 4.19995" stroke="#444d5e" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
725 <?php esc_html_e( 'Conversion Templates', 'wpfnl' ); ?>
726 </li>
727 </ul>
728
729 <div class="create-new-funnel">
730 <a href="#" id="wpfnl-create-store-checkout"
731 class="btn-default add-new-funnel-btn">
732 <?php require WPFNL_DIR . '/admin/partials/icons/plus-icon.php'; ?>
733 <?php esc_html_e( 'Store Checkout', 'wpfnl' ); ?>
734 </a>
735 </div>
736 </div>
737
738 <div class="video-wrapper">
739 <div class="video-preview" tabindex="0" role="button" aria-label="Play video">
740 <img
741 src="<?php echo esc_url( WPFNL_URL . 'admin/assets/images/no-funnel-video-poster.webp' ); ?>"
742 alt="no-funnel-video-poster"
743 class="video-poster"
744 width="569"
745 height="373"
746 />
747
748 <div class="play-overlay">
749 <div class="play-button no-funnel-play-button">
750 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="20" viewBox="0 0 16 20" fill="none"><path d="M14.408 7.19013L3.24942 0.312012C2.93046 0.110674 2.56721 0.00302319 2.19661 0C1.61403 0 1.05532 0.246909 0.643373 0.686411C0.231428 1.12591 0 1.722 0 2.34355V17.1052C7.40914e-05 17.5176 0.10371 17.9225 0.300131 18.2778C0.496553 18.6331 0.778589 18.9257 1.11691 19.1253C1.45524 19.3249 1.8375 19.4241 2.22396 19.4127C2.61041 19.4013 2.98695 19.2797 3.31441 19.0604L14.4859 11.5306C14.8333 11.2986 15.1184 10.9746 15.3135 10.5902C15.5086 10.2057 15.607 9.77389 15.5992 9.33678C15.5913 8.89967 15.4775 8.47219 15.2687 8.09598C15.0599 7.71978 14.7634 7.40769 14.408 7.19013Z" fill="#6e42d3"/></svg>
751 </div>
752 </div>
753 </div>
754
755 <!-- Video Popup -->
756 <div id="no-funnel-video-popup" class="video-popup-overlay" role="dialog" aria-modal="true" aria-labelledby="video-popup-title">
757 <div class="video-popup-content">
758 <button class="video-popup-close" aria-label="Close video">
759 <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
760 <path d="M1 1L13 13M13 1L1 13" stroke="#1D2327" stroke-width="2" stroke-linecap="round"/>
761 </svg>
762 </button>
763 <h2 id="video-popup-title" class="visually-hidden"><?php esc_html_e( 'Video Tutorial', 'wpfnl' ); ?></h2>
764 <div class="video-container">
765 <iframe
766 id="no-funnel-video-iframe"
767 width="550"
768 height="310"
769 src=""
770 data-src="https://www.youtube.com/embed/GrzIRl5jfBE?autoplay=1"
771 title="WPFunnels Store Checkout Tutorial"
772 frameborder="0"
773 allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
774 allowfullscreen
775 ></iframe>
776 </div>
777 </div>
778 </div>
779 </div>
780 </div>
781 </div>
782 <?php endif; ?>
783
784 <?php endif; ?>
785
786 </div><!-- /funnel-list__wrapper -->
787 </div><!-- /wpfnl-dashboard__inner-content -->
788
789 <!-- Toaster -->
790 <div id="wpfnl-toaster-wrapper">
791 <div class="quick-toastify-alert-toast">
792 <div class="quick-toastify-alert-container">
793 <div class="quick-toastify-successfull-icon" id="wpfnl-toaster-icon"></div>
794 <p id="wpfnl-toaster-message"></p>
795 <div class="quick-toastify-cross-icon" id="wpfnl-toaster-close-btn">
796 <svg width="10" height="10" fill="none" viewBox="0 0 10 10" xmlns="http://www.w3.org/2000/svg">
797 <path fill="#686f7f" d="M.948 9.995a.94.94 0 01-.673-.23.966.966 0 010-1.352L8.317.278a.94.94 0 011.339.045c.323.35.342.887.044 1.258L1.611 9.765a.94.94 0 01-.663.23z"/>
798 <path fill="#686f7f" d="M8.98 9.995a.942.942 0 01-.664-.278L.275 1.582A.966.966 0 01.378.23a.939.939 0 011.232 0L9.7 8.366a.966.966 0 010 1.399.94.94 0 01-.72.23z"/>
799 </svg>
800 </div>
801 </div>
802 </div>
803 </div>
804
805 </div><!-- /.dashboard-nav__content -->
806 </div>
807 </div>
808
809 <style>
810 /* Analytics icon-wrap: blue variant */
811 .wpfnl-sc-analytics-overview .wpfnl-sc-analytics-card__icon .icon-wrap--blue {
812 background: linear-gradient(135deg, #EFF6FF 0%, #DBEAFE 100%);
813 border: 1px solid #BFDBFE;
814 }
815
816 /* Enabled status — green pill */
817 .wpfnl-store-checkout-listing-page .funnel-list__wrapper .funnel__single-list .wpfnl-status.enabled .post-status {
818 background: rgba(35, 150, 84, 0.1);
819 color: #239654;
820 }
821
822 /* Page title */
823 .wpfnl-sc-page-title {
824 font-size: 16px;
825 font-weight: 600;
826 color: #363B4E;
827 margin: 0;
828 line-height: 1.4;
829 }
830
831 /* ── Name cell layout ─────────────────────────────────────── */
832 .wpfnl-store-checkout-listing-page .wpfnl-sc-name-cell {
833 display: flex;
834 flex-direction: row;
835 align-items: center;
836 gap: 10px;
837 }
838 .wpfnl-store-checkout-listing-page .wpfnl-sc-name-inner {
839 display: flex;
840 flex-direction: column;
841 min-width: 0;
842 gap: 4px;
843 }
844
845 /* ── Condition line (single row, ellipsis) ────────────────── */
846 .wpfnl-store-checkout-listing-page .sc-condition-line {
847 display: inline-flex;
848 align-items: center;
849 max-width: 100%;
850 cursor: default;
851 }
852 .wpfnl-store-checkout-listing-page .sc-condition-line__text {
853 font-size: 12px;
854 line-height: 1.25;
855 font-weight: 500;
856 text-transform: capitalize;
857 border-radius: 100px;
858 padding: 4px 10px;
859 display: inline-block;
860 max-width: 260px;
861 overflow: hidden;
862 text-overflow: ellipsis;
863 white-space: nowrap;
864 }
865 /* Active condition — green pill (like Published) */
866 .wpfnl-store-checkout-listing-page .sc-condition-line--active .sc-condition-line__text {
867 background: rgba(35, 150, 84, 0.1);
868 color: #239654;
869 }
870 /* No condition — gray pill (like Draft) */
871 .wpfnl-store-checkout-listing-page .sc-condition-line--inactive .sc-condition-line__text {
872 background: rgba(122, 139, 154, 0.15);
873 color: #7A8B9A;
874 }
875
876 /* ── Priority badge (pill, follows Published pattern) ─────── */
877 .wpfnl-store-checkout-listing-page .wpfnl-sc-priority {
878 width: 100px;
879 }
880 .wpfnl-store-checkout-listing-page .list-body .wpfnl-sc-priority {
881 display: flex;
882 align-items: center;
883 }
884 .wpfnl-store-checkout-listing-page .sc-priority-badge {
885 font-size: 12px;
886 line-height: 1.25;
887 font-weight: 500;
888 text-transform: capitalize;
889 border-radius: 100px;
890 display: inline-block;
891 padding: 5px 10px 4px;
892 cursor: default;
893 white-space: nowrap;
894 }
895 /* Active priority (Highest / #N) — purple pill */
896 .wpfnl-store-checkout-listing-page .sc-priority-badge--active {
897 background: rgba(110, 66, 211, 0.1);
898 color: #6E42D3;
899 }
900 /* Fallback — gray pill */
901 .wpfnl-store-checkout-listing-page .sc-priority-badge--fallback {
902 background: rgba(122, 139, 154, 0.15);
903 color: #7A8B9A;
904 }
905 /* Overridden — red/muted pill */
906 .wpfnl-store-checkout-listing-page .sc-priority-badge--overridden {
907 background: rgba(220, 53, 69, 0.1);
908 color: #DC3545;
909 }
910
911 /* ── Condition line tooltip ───────────────────────────────── */
912 .wpfnl-store-checkout-listing-page .sc-condition-line {
913 position: relative;
914 }
915 .wpfnl-store-checkout-listing-page .sc-condition-line__tooltip {
916 position: absolute;
917 bottom: calc(100% + 10px);
918 left: 0;
919 background: #0C1015;
920 border-radius: 6px;
921 padding: 7px 10px;
922 color: #fff;
923 font-size: 12px;
924 font-weight: 400;
925 line-height: 1.4;
926 white-space: normal;
927 width: 240px;
928 z-index: 4;
929 opacity: 0;
930 visibility: hidden;
931 transition: all 0.3s ease;
932 pointer-events: none;
933 }
934 .wpfnl-store-checkout-listing-page .sc-condition-line__tooltip:before {
935 content: "";
936 position: absolute;
937 left: 16px;
938 bottom: -4px;
939 width: 10px;
940 height: 10px;
941 background: #0C1015;
942 transform: rotate(45deg);
943 border-radius: 2px;
944 }
945 .wpfnl-store-checkout-listing-page .sc-condition-line:hover .sc-condition-line__tooltip {
946 opacity: 1;
947 visibility: visible;
948 }
949
950 /* ── Priority badge tooltip ───────────────────────────────── */
951 .wpfnl-store-checkout-listing-page .sc-priority-badge {
952 position: relative;
953 }
954 .wpfnl-store-checkout-listing-page .sc-priority-badge__tooltip {
955 position: absolute;
956 bottom: calc(100% + 10px);
957 left: 50%;
958 transform: translateX(-50%);
959 background: #0C1015;
960 border-radius: 6px;
961 padding: 7px 10px;
962 color: #fff;
963 font-size: 12px;
964 font-weight: 400;
965 line-height: 1.4;
966 white-space: normal;
967 width: 200px;
968 z-index: 4;
969 opacity: 0;
970 visibility: hidden;
971 transition: all 0.3s ease;
972 pointer-events: none;
973 }
974 .wpfnl-store-checkout-listing-page .sc-priority-badge__tooltip:before {
975 content: "";
976 position: absolute;
977 left: 50%;
978 bottom: -4px;
979 width: 10px;
980 height: 10px;
981 background: #0C1015;
982 transform: rotate(45deg) translateX(-50%);
983 border-radius: 2px;
984 }
985 .wpfnl-store-checkout-listing-page .sc-priority-badge:hover .sc-priority-badge__tooltip {
986 opacity: 1;
987 visibility: visible;
988 }
989 </style>
990
991 <script type="text/javascript">
992 (function ($) {
993 'use strict';
994
995 var scListingUrl = <?php echo wp_json_encode( esc_url_raw( $sc_listing_url ) ); ?>;
996 var scTrashUrl = <?php echo wp_json_encode( esc_url_raw( $sc_trash_url ) ); ?>;
997 var scView = <?php echo wp_json_encode( $sc_view ); ?>;
998
999 $(document).ready(function () {
1000
1001 // ── Analytics toggle ────────────────────────────────────────────
1002 $('.wpfnl-sc-analytics-toggle').on('click', function () {
1003 $('.wpfnl-sc-analytics-overview').toggleClass('collapsed');
1004 });
1005
1006 // ── Bulk selection ──────────────────────────────────────────────
1007 var selectedScIds = [];
1008
1009 function updateScBulkBar() {
1010 var count = selectedScIds.length;
1011 if ( count > 0 ) {
1012 $('.funnel__single-list.list-header .bulk-action-wrapper').css('display', 'flex');
1013 } else {
1014 $('.funnel__single-list.list-header .bulk-action-wrapper').css('display', 'none');
1015 }
1016 $('.selected-funnel-count').text( count + ' ' + (count === 1 ? 'Store Checkout' : 'Store Checkouts') );
1017 }
1018
1019 // Master checkbox: select / deselect all visible rows
1020 $(document).on('change', '#wpfnl-sc-bulk-select', function () {
1021 var checked = $(this).is(':checked');
1022 $('input[name="wpfnl-sc-list-select"]').each(function () {
1023 $(this).prop('checked', checked);
1024 var id = parseInt( $(this).data('id'), 10 );
1025 if ( checked ) {
1026 if ( selectedScIds.indexOf(id) === -1 ) {
1027 selectedScIds.push(id);
1028 }
1029 } else {
1030 selectedScIds = selectedScIds.filter(function (v) { return v !== id; });
1031 }
1032 });
1033 updateScBulkBar();
1034 });
1035
1036 // Per-row checkbox
1037 $(document).on('change', 'input[name="wpfnl-sc-list-select"]', function () {
1038 var id = parseInt( $(this).data('id'), 10 );
1039 if ( $(this).is(':checked') ) {
1040 if ( selectedScIds.indexOf(id) === -1 ) {
1041 selectedScIds.push(id);
1042 }
1043 } else {
1044 selectedScIds = selectedScIds.filter(function (v) { return v !== id; });
1045 $('#wpfnl-sc-bulk-select').prop('checked', false);
1046 }
1047 updateScBulkBar();
1048 });
1049
1050 // Bulk trash
1051 $(document).on('click', '.wpfnl-sc-bulk-trash', function (e) {
1052 e.preventDefault();
1053 if ( selectedScIds.length === 0 ) return;
1054 if ( ! confirm('Are you sure you want to trash the selected store checkouts?') ) return;
1055
1056 var ids = selectedScIds.slice();
1057 var done = 0;
1058 var failed = 0;
1059
1060 ids.forEach(function (funnel_id) {
1061 wpAjaxHelperRequest('trash-funnel', { funnel_id: funnel_id })
1062 .success(function () {
1063 done++;
1064 if ( done + failed === ids.length ) {
1065 localStorage.setItem('wpfnl_show_toast', 'trash_success');
1066 window.location.href = scListingUrl;
1067 }
1068 })
1069 .error(function () {
1070 failed++;
1071 if ( done + failed === ids.length ) {
1072 window.location.href = scListingUrl;
1073 }
1074 });
1075 });
1076 });
1077
1078 // ── End bulk selection ──────────────────────────────────────────
1079
1080 // Create store checkout — open template library
1081 $(document).on('click', '#wpfnl-create-store-checkout', function (e) {
1082 e.preventDefault();
1083 window.wpfnlStoreCheckoutMode = true;
1084 setTimeout(function () {
1085 $('#template-library-modal').show();
1086 $('#wpfnl-create-funnel__inner-content').show();
1087 $('#wpfnl-create-steps_inner-content').hide();
1088 }, 100);
1089 });
1090
1091 // Toggle status: Publish ↔ Move to Draft
1092 // Use direct binding — delegated $(document).on() is blocked by
1093 // stopPropagation() in wpfnl-admin.js on .wpfnl-dropdown.
1094 $('.wpfnl-sc-status-toggle').on('click', function (e) {
1095 e.preventDefault();
1096 var funnel_id = $(this).data('id');
1097 var new_status = $(this).data('status');
1098 if ( ! confirm('Are you sure?') ) return;
1099 wpAjaxHelperRequest('update-funnel-status', { funnel_id: funnel_id, status: new_status })
1100 .success(function () {
1101 localStorage.setItem('wpfnl_show_toast', 'status_updated');
1102 window.location.href = scListingUrl;
1103 })
1104 .error(function () {
1105 console.error('Status update failed.');
1106 });
1107 });
1108
1109 // Trash store checkout funnel
1110 $('.wpfnl-sc-trash-funnel').on('click', function (e) {
1111 e.preventDefault();
1112 var funnel_id = $(this).data('id');
1113 if ( ! confirm('Are you sure you want to trash this store checkout?') ) return;
1114 wpAjaxHelperRequest('trash-funnel', { funnel_id: funnel_id })
1115 .success(function () {
1116 localStorage.setItem('wpfnl_show_toast', 'trash_success');
1117 window.location.href = scListingUrl;
1118 })
1119 .error(function () {
1120 console.error('Trash failed.');
1121 });
1122 });
1123
1124 // Restore store checkout funnel
1125 $('.wpfnl-sc-restore-funnel').on('click', function (e) {
1126 e.preventDefault();
1127 var funnel_id = $(this).data('id');
1128 if ( ! confirm('Are you sure you want to restore this store checkout?') ) return;
1129 wpAjaxHelperRequest('restore-funnel', { funnel_id: funnel_id })
1130 .success(function () {
1131 localStorage.setItem('wpfnl_show_toast', 'restore_success');
1132 window.location.href = scTrashUrl;
1133 })
1134 .error(function () {
1135 console.error('Restore failed.');
1136 });
1137 });
1138
1139 // Delete store checkout funnel permanently
1140 $('.wpfnl-sc-delete-funnel').on('click', function (e) {
1141 e.preventDefault();
1142 var funnel_id = $(this).data('id');
1143 if ( ! confirm('Are you sure you want to permanently delete this store checkout? This cannot be undone.') ) return;
1144 wpAjaxHelperRequest('delete-funnel', { funnel_id: funnel_id })
1145 .success(function () {
1146 localStorage.setItem('wpfnl_show_toast', 'delete_success');
1147 window.location.href = scTrashUrl;
1148 })
1149 .error(function () {
1150 console.error('Delete failed.');
1151 });
1152 });
1153
1154 // Bulk restore
1155 $(document).on('click', '.wpfnl-sc-bulk-restore', function (e) {
1156 e.preventDefault();
1157 if ( selectedScIds.length === 0 ) return;
1158 if ( ! confirm('Are you sure you want to restore the selected store checkouts?') ) return;
1159
1160 var ids = selectedScIds.slice(), done = 0, failed = 0;
1161 ids.forEach(function (funnel_id) {
1162 wpAjaxHelperRequest('restore-funnel', { funnel_id: funnel_id })
1163 .success(function () {
1164 done++;
1165 if ( done + failed === ids.length ) {
1166 localStorage.setItem('wpfnl_show_toast', 'restore_success');
1167 window.location.href = scTrashUrl;
1168 }
1169 })
1170 .error(function () {
1171 failed++;
1172 if ( done + failed === ids.length ) { window.location.href = scTrashUrl; }
1173 });
1174 });
1175 });
1176
1177 // Bulk delete permanently
1178 $(document).on('click', '.wpfnl-sc-bulk-delete', function (e) {
1179 e.preventDefault();
1180 if ( selectedScIds.length === 0 ) return;
1181 if ( ! confirm('Are you sure you want to permanently delete the selected store checkouts? This cannot be undone.') ) return;
1182
1183 var ids = selectedScIds.slice(), done = 0, failed = 0;
1184 ids.forEach(function (funnel_id) {
1185 wpAjaxHelperRequest('delete-funnel', { funnel_id: funnel_id })
1186 .success(function () {
1187 done++;
1188 if ( done + failed === ids.length ) {
1189 localStorage.setItem('wpfnl_show_toast', 'delete_success');
1190 window.location.href = scTrashUrl;
1191 }
1192 })
1193 .error(function () {
1194 failed++;
1195 if ( done + failed === ids.length ) { window.location.href = scTrashUrl; }
1196 });
1197 });
1198 });
1199
1200 // Per-page selector
1201 $(document).on('change', '#wpfnl-sc-per-page', function () {
1202 var pp = $(this).val();
1203 var url = new URL( scView === 'trash' ? scTrashUrl : scListingUrl );
1204 url.searchParams.set('per_page', pp);
1205 url.searchParams.set('pageno', 1);
1206 window.location.href = url.toString();
1207 });
1208
1209 });
1210 })(jQuery);
1211 </script>
1212