PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.0.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.0.0
2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
← All changes | includes/Admin/AdminComponents.php +174 -0 1.11.22.0.0 View file →
@@ -1,7 +1,85 @@
1 1 <?php
2 +/**
3 + * Shared admin UI component renderers.
4 + *
5 + * @package SpringDevs\Subscription\Admin
6 + */
2 7
8 +// Exit if accessed directly.
9 +if ( ! defined( 'ABSPATH' ) ) {
10 + exit;
11 +}
12 +
3 13 /**
14 + * Render the standard admin page header: title, optional description, optional
15 + * right-aligned actions, an optional right-hand aside (e.g. stat cards), and a
16 + * dashed rule beneath. The one header for every admin screen in both plugins —
17 + * use this instead of hand-writing the markup on a new page.
18 + *
19 + * @param array $args {
20 + * Header args.
21 + *
22 + * @type string $title Page title. Required.
23 + * @type string $description One-line description under the title.
24 + * @type string $doc_url Docs URL; appends a "view documentation" link to
25 + * the description.
26 + * @type string $actions Pre-escaped HTML on the right of the title row.
27 + * @type string $aside Pre-escaped HTML for a right-hand column beside
28 + * the header (e.g. stat cards).
29 + * @type string $class Extra classes on the wrapper.
30 + * }
31 + * @return void
32 + */
33 +function wpsubs_render_page_header( array $args ): void {
34 + $args = wp_parse_args(
35 + $args,
36 + array(
37 + 'title' => '',
38 + 'description' => '',
39 + 'doc_url' => '',
40 + 'actions' => '',
41 + 'aside' => '',
42 + 'class' => '',
43 + )
44 + );
45 +
46 + $classes = 'wpsubs-page-header';
47 + if ( '' !== $args['aside'] ) {
48 + $classes .= ' wpsubs-page-header--has-aside';
49 + }
50 + if ( $args['class'] ) {
51 + $classes .= ' ' . $args['class'];
52 + }
53 + ?>
54 + <div class="<?php echo esc_attr( $classes ); ?>">
55 + <div class="wpsubs-page-header__main">
56 + <div class="wpsubs-page-header__row">
57 + <h1 class="wpsubs-page-header__title"><?php echo esc_html( $args['title'] ); ?></h1>
58 + <?php if ( '' !== $args['actions'] ) : ?>
59 + <span class="wpsubs-toolbar__spacer"></span>
60 + <?php echo $args['actions']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- caller passes pre-escaped markup. ?>
61 + <?php endif; ?>
62 + </div>
63 + <?php if ( '' !== $args['description'] ) : ?>
64 + <p class="wpsubs-page-header__desc">
65 + <?php echo esc_html( $args['description'] ); ?>
66 + <?php if ( '' !== $args['doc_url'] ) : ?>
67 + <?php esc_html_e( 'For more information,', 'subscription' ); ?>
68 + <a href="<?php echo esc_url( $args['doc_url'] ); ?>" target="_blank" rel="noopener"><?php esc_html_e( 'view documentation', 'subscription' ); ?></a>.
69 + <?php endif; ?>
70 + </p>
71 + <?php endif; ?>
72 + <div class="wpsubs-page-header__rule"></div>
73 + </div>
74 + <?php if ( '' !== $args['aside'] ) : ?>
75 + <div class="wpsubs-page-header__aside"><?php echo $args['aside']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- caller passes pre-escaped markup. ?></div>
76 + <?php endif; ?>
77 + </div>
78 + <?php
79 +}
80 +
81 +/**
4 82 * Compute the visible page list for a paginator (current ± 1 window with
5 83 * ellipsis for wider gaps, page 1 and the last page always pinned).
6 84 *
7 85 * Mirrors the JS algorithm used by WPSubsPager so server- and client-side
@@ -610,8 +688,56 @@
610 688 <?php
611 689 }
612 690
613 691 /**
692 + * Render a "per page" selector as an Advanced Select.
693 + *
694 + * Wraps wpsubs_render_adv_select() with the project-standard page-size options
695 + * (10 / 20 / 50 / 100) so every list uses the same choices. Everything is
696 + * overridable: pass `options` (an array of ints, or full adv-select option
697 + * arrays) to change the choices, `value` for the initial selection, and any
698 + * other wpsubs_render_adv_select() arg (name, align, id, class, attrs) — they
699 + * pass straight through.
700 + *
701 + * @param array $args {
702 + * @type string $name Hidden input name.
703 + * @type string $value Initial value. Default '10'.
704 + * @type array $options Page sizes (ints) or option arrays. Default 10/20/50/100.
705 + * @type mixed ... Any other wpsubs_render_adv_select() arg.
706 + * }
707 + *
708 + * @return void
709 + */
710 +function wpsubs_render_per_page_select( array $args = array() ): void {
711 + $args = array_merge(
712 + array(
713 + 'value' => '10',
714 + 'options' => array( 10, 20, 50, 100 ),
715 + ),
716 + $args
717 + );
718 +
719 + // Expand plain int page sizes into adv-select option arrays.
720 + $options = array();
721 + foreach ( $args['options'] as $option ) {
722 + if ( is_array( $option ) ) {
723 + $options[] = $option;
724 + continue;
725 + }
726 + $options[] = array(
727 + 'value' => (string) $option,
728 + /* translators: %d: number of items shown per page. */
729 + 'label' => sprintf( __( '%d / page', 'subscription' ), (int) $option ),
730 + );
731 + }
732 +
733 + $args['options'] = $options;
734 + $args['value'] = (string) $args['value'];
735 +
736 + wpsubs_render_adv_select( $args );
737 +}
738 +
739 +/**
614 740 * Render a tag/pill select input with an inline filter and filterable dropdown.
615 741 * Supports single and multiple selection. No external dependencies.
616 742 *
617 743 * JS: WPSubsTagSelect (admin-components.js) auto-inits elements.
@@ -817,5 +943,53 @@
817 943 <?php endif; ?>
818 944 </div>
819 945 </div>
820 946 <?php
947 +}
948 +
949 +/**
950 + * Render an inline help hint: a help icon that reveals text on hover.
951 + *
952 + * Thin wrapper over the canonical `wpsubs-tooltip` component
953 + * (admin-components/tooltip.css): a help dashicon wrapped in a data-tip span.
954 + * Returns the markup so it can be concatenated into a label; place it inside an
955 + * overflow:visible container so the bubble is not clipped.
956 + *
957 + * @param string $text Hint text.
958 + * @param array $args Optional. 'placement' => 'top' (default)|'bottom'|'left'|'right';
959 + * 'align' => 'center' (default)|'start'|'end'; 'class' => extra trigger classes.
960 + *
961 + * @return string Escaped markup.
962 + */
963 +function wpsubs_render_hint( string $text, array $args = array() ): string {
964 + $args = wp_parse_args(
965 + $args,
966 + array(
967 + 'placement' => 'top',
968 + 'align' => 'center',
969 + 'class' => '',
970 + )
971 + );
972 +
973 + $classes = 'wpsubs-tooltip wpsubs-tooltip--hint';
974 + if ( in_array( $args['placement'], array( 'bottom', 'left', 'right' ), true ) ) {
975 + $classes .= ' wpsubs-tooltip--' . $args['placement'];
976 + }
977 + if ( in_array( $args['align'], array( 'start', 'end' ), true ) ) {
978 + $classes .= ' wpsubs-tooltip--' . $args['align'];
979 + }
980 + if ( '' !== $args['class'] ) {
981 + $classes .= ' ' . $args['class'];
982 + }
983 +
984 + // A <span> (not a <button>/<input>) is NOT a labelable element, so nesting
985 + // it inside a <label> does not associate the label with it — hovering the
986 + // label text therefore never reveals the tooltip, only hovering the icon
987 + // does. The text is exposed to assistive tech via role="img" + aria-label.
988 + return sprintf(
989 + '<span class="%1$s" data-tip="%2$s" role="img" aria-label="%2$s">'
990 + . '<span class="dashicons dashicons-editor-help wpsubs-tooltip__icon" aria-hidden="true"></span>'
991 + . '</span>',
992 + esc_attr( $classes ),
993 + esc_attr( $text )
994 + );
821 995 }