PluginProbe
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.5.2
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.5.2
2.12.6 2.12.5 2.12.4 2.12.3 2.12.2 2.12.1 2.12.0 2.11.1 2.11.0 2.10.1 2.10.0 2.9.1 2.9.0 2.8.2 2.8.1 2.7.0 2.7.1 2.8.0 trunk 0.0.10 0.0.11 0.0.12 0.0.13 0.0.2 0.0.3 All 96 releases
sureforms / inc / abilities / forms / list-forms.php
list-forms.php
203 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * List Forms Ability.
4 *
5 * @package sureforms
6 * @since 2.5.2
7 */
8
9 namespace SRFM\Inc\Abilities\Forms;
10
11 use SRFM\Inc\Abilities\Abstract_Ability;
12 use SRFM\Inc\Helper;
13 use WP_Query;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 /**
20 * List_Forms ability class.
21 *
22 * Lists all SureForms forms with optional filtering.
23 *
24 * @since 2.5.2
25 */
26 class List_Forms extends Abstract_Ability {
27 /**
28 * Constructor.
29 *
30 * @since 2.5.2
31 */
32 public function __construct() {
33 $this->id = 'sureforms/list-forms';
34 $this->label = __( 'List SureForms Forms', 'sureforms' );
35 $this->description = __( 'Retrieve a list of SureForms forms with optional filtering by status, search query, and pagination.', 'sureforms' );
36 $this->capability = 'manage_options';
37 }
38
39 /**
40 * {@inheritDoc}
41 */
42 public function get_annotations() {
43 return [
44 'readonly' => true,
45 'destructive' => false,
46 'idempotent' => true,
47 ];
48 }
49
50 /**
51 * {@inheritDoc}
52 */
53 public function get_input_schema() {
54 return [
55 'type' => 'object',
56 'properties' => [
57 'status' => [
58 'type' => 'string',
59 'description' => __( 'Filter by form status. Defaults to "publish".', 'sureforms' ),
60 'enum' => [ 'publish', 'draft', 'trash', 'any' ],
61 'default' => 'any',
62 ],
63 'search' => [
64 'type' => 'string',
65 'description' => __( 'Search forms by title.', 'sureforms' ),
66 ],
67 'per_page' => [
68 'type' => 'integer',
69 'description' => __( 'Number of forms per page. Defaults to 10.', 'sureforms' ),
70 'default' => 10,
71 'minimum' => 1,
72 'maximum' => 100,
73 ],
74 'page' => [
75 'type' => 'integer',
76 'description' => __( 'Page number for pagination. Defaults to 1.', 'sureforms' ),
77 'default' => 1,
78 'minimum' => 1,
79 ],
80 ],
81 ];
82 }
83
84 /**
85 * {@inheritDoc}
86 */
87 public function get_output_schema() {
88 return [
89 'type' => 'object',
90 'properties' => [
91 'forms' => [
92 'type' => 'array',
93 'items' => [
94 'type' => 'object',
95 'properties' => [
96 'id' => [ 'type' => 'integer' ],
97 'title' => [ 'type' => 'string' ],
98 'status' => [ 'type' => 'string' ],
99 'date' => [ 'type' => 'string' ],
100 'entry_count' => [ 'type' => 'integer' ],
101 ],
102 ],
103 ],
104 'total' => [ 'type' => 'integer' ],
105 'pages' => [ 'type' => 'integer' ],
106 ],
107 ];
108 }
109
110 /**
111 * Execute the list-forms ability.
112 *
113 * @param array<string,mixed> $input Validated input data.
114 * @return array<string,mixed>|\WP_Error
115 */
116 public function execute( $input ) {
117 $status = ! empty( $input['status'] ) ? sanitize_text_field( Helper::get_string_value( $input['status'] ) ) : 'any';
118 $search = ! empty( $input['search'] ) ? sanitize_text_field( Helper::get_string_value( $input['search'] ) ) : '';
119 $per_page = ! empty( $input['per_page'] ) ? Helper::get_integer_value( $input['per_page'] ) : 10;
120 $page = ! empty( $input['page'] ) ? Helper::get_integer_value( $input['page'] ) : 1;
121
122 $per_page = max( 1, min( 100, $per_page ) );
123
124 $query_args = [
125 'post_type' => SRFM_FORMS_POST_TYPE,
126 'post_status' => $status,
127 'posts_per_page' => $per_page,
128 'paged' => $page,
129 'orderby' => 'date',
130 'order' => 'DESC',
131 ];
132
133 if ( ! empty( $search ) ) {
134 $query_args['s'] = $search;
135 }
136
137 $query = new WP_Query( $query_args );
138 $forms = [];
139
140 if ( $query->have_posts() ) {
141 $form_ids = wp_list_pluck( $query->posts, 'ID' );
142 $entry_counts = $this->get_entry_counts( $form_ids );
143
144 foreach ( $query->posts as $post ) {
145 if ( ! $post instanceof \WP_Post ) {
146 continue;
147 }
148
149 $forms[] = [
150 'id' => $post->ID,
151 'title' => $post->post_title,
152 'status' => $post->post_status,
153 'date' => $post->post_date,
154 'entry_count' => $entry_counts[ $post->ID ] ?? 0,
155 ];
156 }
157 }
158
159 return [
160 'forms' => $forms,
161 'total' => $query->found_posts,
162 'pages' => $query->max_num_pages,
163 ];
164 }
165
166 /**
167 * Get entry counts for multiple forms in a single query.
168 *
169 * @param array<int> $form_ids Array of form IDs.
170 * @since 2.5.2
171 * @return array<int,int> Map of form_id => entry count.
172 */
173 private function get_entry_counts( array $form_ids ) {
174 if ( empty( $form_ids ) ) {
175 return [];
176 }
177
178 global $wpdb;
179
180 $table_name = $wpdb->prefix . 'srfm_entries';
181 $placeholders = implode( ',', array_fill( 0, count( $form_ids ), '%d' ) );
182
183 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Batch query to avoid N+1; results are not cached as they reflect real-time entry counts.
184 $results = $wpdb->get_results(
185 $wpdb->prepare(
186 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Table name and placeholders are constructed from $wpdb->prefix and array_fill(), not user input.
187 "SELECT form_id, COUNT(*) as cnt FROM {$table_name} WHERE form_id IN ({$placeholders}) AND status != 'trash' GROUP BY form_id",
188 ...$form_ids
189 ),
190 ARRAY_A
191 );
192
193 $counts = [];
194 if ( is_array( $results ) ) {
195 foreach ( $results as $row ) {
196 $counts[ (int) $row['form_id'] ] = (int) $row['cnt'];
197 }
198 }
199
200 return $counts;
201 }
202 }
203