PluginProbe ʕ •ᴥ•ʔ
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz / 2.12.3
SureForms – Contact Form Builder, AI Forms, Payment Form, Survey & Quiz v2.12.3
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 0.0.4 0.0.5 0.0.6 0.0.7 0.0.8 0.0.9 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.1.0 1.1.1 1.1.2 1.10.0 1.10.1 1.11.0 1.12.0 1.12.1 1.12.2 1.12.3 1.13.0 1.13.1 1.13.2 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.5.0 1.5.1 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.8.0 1.9.0 1.9.1 2.0.0 2.0.1 2.0.2 2.1.0 2.1.1 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.5.0 2.5.2 2.6.0
sureforms / inc / abilities / forms / list-forms.php
sureforms / inc / abilities / forms Last commit date
create-form.php 1 month ago delete-form.php 5 months ago duplicate-form.php 5 months ago form-field-schema.php 2 months ago form-metadata.php 1 month ago get-form-stats.php 5 months ago get-form.php 5 months ago get-shortcode.php 5 months ago list-forms.php 2 months ago update-form.php 1 month ago
list-forms.php
206 lines
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 'priority' => 1.0,
48 'openWorldHint' => false,
49 ];
50 }
51
52 /**
53 * {@inheritDoc}
54 */
55 public function get_input_schema() {
56 return [
57 'type' => 'object',
58 'additionalProperties' => false,
59 'properties' => [
60 'status' => [
61 'type' => 'string',
62 'description' => __( 'Filter by form status. Defaults to "publish".', 'sureforms' ),
63 'enum' => [ 'publish', 'draft', 'trash', 'any' ],
64 'default' => 'any',
65 ],
66 'search' => [
67 'type' => 'string',
68 'description' => __( 'Search forms by title.', 'sureforms' ),
69 ],
70 'per_page' => [
71 'type' => 'integer',
72 'description' => __( 'Number of forms per page. Defaults to 10.', 'sureforms' ),
73 'default' => 10,
74 'minimum' => 1,
75 'maximum' => 100,
76 ],
77 'page' => [
78 'type' => 'integer',
79 'description' => __( 'Page number for pagination. Defaults to 1.', 'sureforms' ),
80 'default' => 1,
81 'minimum' => 1,
82 ],
83 ],
84 ];
85 }
86
87 /**
88 * {@inheritDoc}
89 */
90 public function get_output_schema() {
91 return [
92 'type' => 'object',
93 'properties' => [
94 'forms' => [
95 'type' => 'array',
96 'items' => [
97 'type' => 'object',
98 'properties' => [
99 'id' => [ 'type' => 'integer' ],
100 'title' => [ 'type' => 'string' ],
101 'status' => [ 'type' => 'string' ],
102 'date' => [ 'type' => 'string' ],
103 'entry_count' => [ 'type' => 'integer' ],
104 ],
105 ],
106 ],
107 'total' => [ 'type' => 'integer' ],
108 'pages' => [ 'type' => 'integer' ],
109 ],
110 ];
111 }
112
113 /**
114 * Execute the list-forms ability.
115 *
116 * @param array<string,mixed> $input Validated input data.
117 * @return array<string,mixed>|\WP_Error
118 */
119 public function execute( $input ) {
120 $status = ! empty( $input['status'] ) ? sanitize_text_field( Helper::get_string_value( $input['status'] ) ) : 'any';
121 $search = ! empty( $input['search'] ) ? sanitize_text_field( Helper::get_string_value( $input['search'] ) ) : '';
122 $per_page = ! empty( $input['per_page'] ) ? Helper::get_integer_value( $input['per_page'] ) : 10;
123 $page = ! empty( $input['page'] ) ? Helper::get_integer_value( $input['page'] ) : 1;
124
125 $per_page = max( 1, min( 100, $per_page ) );
126
127 $query_args = [
128 'post_type' => SRFM_FORMS_POST_TYPE,
129 'post_status' => $status,
130 'posts_per_page' => $per_page,
131 'paged' => $page,
132 'orderby' => 'date',
133 'order' => 'DESC',
134 ];
135
136 if ( ! empty( $search ) ) {
137 $query_args['s'] = $search;
138 }
139
140 $query = new WP_Query( $query_args );
141 $forms = [];
142
143 if ( $query->have_posts() ) {
144 $form_ids = wp_list_pluck( $query->posts, 'ID' );
145 $entry_counts = $this->get_entry_counts( $form_ids );
146
147 foreach ( $query->posts as $post ) {
148 if ( ! $post instanceof \WP_Post ) {
149 continue;
150 }
151
152 $forms[] = [
153 'id' => $post->ID,
154 'title' => $post->post_title,
155 'status' => $post->post_status,
156 'date' => $post->post_date,
157 'entry_count' => $entry_counts[ $post->ID ] ?? 0,
158 ];
159 }
160 }
161
162 return [
163 'forms' => $forms,
164 'total' => $query->found_posts,
165 'pages' => $query->max_num_pages,
166 ];
167 }
168
169 /**
170 * Get entry counts for multiple forms in a single query.
171 *
172 * @param array<int> $form_ids Array of form IDs.
173 * @since 2.5.2
174 * @return array<int,int> Map of form_id => entry count.
175 */
176 private function get_entry_counts( array $form_ids ) {
177 if ( empty( $form_ids ) ) {
178 return [];
179 }
180
181 global $wpdb;
182
183 $table_name = $wpdb->prefix . 'srfm_entries';
184 $placeholders = implode( ',', array_fill( 0, count( $form_ids ), '%d' ) );
185
186 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Batch query to avoid N+1; table name from $wpdb->prefix and placeholders from array_fill() (not user input); results not cached as they reflect real-time entry counts.
187 $results = $wpdb->get_results(
188 $wpdb->prepare(
189 // 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.
190 "SELECT form_id, COUNT(*) as cnt FROM {$table_name} WHERE form_id IN ({$placeholders}) AND status != 'trash' GROUP BY form_id",
191 ...$form_ids
192 ),
193 ARRAY_A
194 );
195
196 $counts = [];
197 if ( is_array( $results ) ) {
198 foreach ( $results as $row ) {
199 $counts[ (int) $row['form_id'] ] = (int) $row['cnt'];
200 }
201 }
202
203 return $counts;
204 }
205 }
206