Skip to content

Commit ad36e38

Browse files
authored
Merge pull request #893 from Kit/form-entries-table-search
Form Builder: Store Entries: Search Submissions
2 parents 3622bf8 + aa9ccd9 commit ad36e38

File tree

7 files changed

+646
-10
lines changed

7 files changed

+646
-10
lines changed

admin/class-convertkit-admin-settings.php

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,28 @@ public function display_settings_page() {
149149
if ( count( $this->sections ) > 1 ) {
150150
$this->display_section_nav( $active_section );
151151
}
152-
?>
153152

154-
<form method="post" action="options.php" enctype="multipart/form-data">
153+
/**
154+
* Defines the settings form's method.
155+
*
156+
* @since 3.0.0
157+
*
158+
* @param string $form_method The method of the form.
159+
* @param string $active_section The active section.
160+
*/
161+
$form_method = apply_filters( 'convertkit_admin_settings_form_method', 'post', $active_section );
162+
163+
/**
164+
* Defines the settings form's action URL.
165+
*
166+
* @since 3.0.0
167+
*
168+
* @param string $form_action_url The URL to submit the form to.
169+
* @param string $active_section The active section.
170+
*/
171+
$form_action_url = apply_filters( 'convertkit_admin_settings_form_action_url', admin_url( 'options.php' ), $active_section );
172+
?>
173+
<form method="<?php echo esc_attr( $form_method ); ?>" action="<?php echo esc_url( $form_action_url ); ?>" enctype="multipart/form-data">
155174
<?php
156175
// Iterate through sections to find the active section to render.
157176
if ( isset( $this->sections[ $active_section ] ) ) {

admin/class-convertkit-wp-list-table.php

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,24 @@
2222
*/
2323
class ConvertKit_WP_List_Table extends WP_List_Table {
2424

25+
/**
26+
* Holds the page query parameter.
27+
*
28+
* @since 3.0.0
29+
*
30+
* @var bool|string
31+
*/
32+
private $page = false;
33+
34+
/**
35+
* Holds the tab query parameter.
36+
*
37+
* @since 3.0.0
38+
*
39+
* @var bool|string
40+
*/
41+
private $tab = false;
42+
2543
/**
2644
* Holds the supported bulk actions.
2745
*
@@ -65,13 +83,19 @@ class ConvertKit_WP_List_Table extends WP_List_Table {
6583
* Constructor.
6684
*
6785
* @since 1.0.0
86+
*
87+
* @param bool|string $page Page query parameter.
88+
* @param bool|string $tab Tab query parameter.
6889
*/
69-
public function __construct() {
90+
public function __construct( $page = false, $tab = false ) {
91+
92+
$this->page = $page;
93+
$this->tab = $tab;
7094

7195
parent::__construct(
7296
array(
73-
'singular' => 'item',
74-
'plural' => 'items',
97+
'singular' => 'convertkit-item',
98+
'plural' => 'convertkit-items',
7599
'ajax' => false,
76100
)
77101
);
@@ -102,8 +126,9 @@ public function column_default( $item, $column_name ) {
102126
public function column_cb( $item ) {
103127

104128
return sprintf(
105-
'<input type="checkbox" name="%1$s[]" value="%2$s" />',
106-
$this->_args['singular'],
129+
'<input type="checkbox" name="%1$s[]" id="cb-select-%2$s" value="%3$s" />',
130+
$this->_args['plural'],
131+
$item['id'],
107132
$item['id']
108133
);
109134

@@ -120,6 +145,36 @@ public function get_bulk_actions() {
120145

121146
}
122147

148+
/**
149+
* Displays the search input field.
150+
*
151+
* @since 3.0.0
152+
*
153+
* @param string $text The 'submit' button label.
154+
* @param string $input_id ID attribute value for the search input field.
155+
*/
156+
public function search_box( $text, $input_id ) {
157+
158+
?>
159+
<p class="search-box">
160+
<label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
161+
<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>" placeholder="<?php esc_attr_e( 'Search', 'convertkit' ); ?>" />
162+
<?php submit_button( $text, 'secondary', 'submit', false, array( 'id' => 'search-submit' ) ); ?>
163+
</p>
164+
<?php
165+
if ( $this->page ) {
166+
?>
167+
<input type="hidden" name="page" value="<?php echo esc_attr( $this->page ); ?>" />
168+
<?php
169+
}
170+
if ( $this->tab ) {
171+
?>
172+
<input type="hidden" name="tab" value="<?php echo esc_attr( $this->tab ); ?>" />
173+
<?php
174+
}
175+
176+
}
177+
123178
/**
124179
* Get a list of columns
125180
*
@@ -272,6 +327,7 @@ public function prepare_items() {
272327
*/
273328
protected function display_tablenav( $which ) {
274329

330+
// Define a nonce for search submissions.
275331
if ( 'top' === $which ) {
276332
wp_nonce_field( 'bulk-' . $this->_args['plural'] );
277333
}
@@ -342,7 +398,7 @@ public function is_search() {
342398
public function get_search() {
343399

344400
// Bail if nonce is not valid.
345-
if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-wp-to-social-log' ) ) {
401+
if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-' . $this->_args['plural'] ) ) {
346402
return '';
347403
}
348404

admin/section/class-convertkit-admin-section-form-entries.php

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,38 @@ public function __construct() {
3737

3838
// Register screen options.
3939
if ( $this->on_settings_screen( $this->name ) ) {
40+
add_filter( 'convertkit_settings_base_register_notices', array( $this, 'register_notices' ) );
41+
add_action( 'convertkit_settings_base_render_before', array( $this, 'maybe_output_notices' ) );
4042
add_action( 'load-settings_page__wp_convertkit_settings', array( $this, 'add_screen_options' ) );
43+
add_action( 'load-settings_page__wp_convertkit_settings', array( $this, 'run_bulk_actions' ) );
44+
add_filter( 'convertkit_admin_settings_form_method', array( $this, 'form_method' ), 10, 2 );
45+
add_filter( 'convertkit_admin_settings_form_action_url', array( $this, 'form_action_url' ), 10, 2 );
4146
}
4247

4348
parent::__construct();
4449

4550
}
4651

52+
/**
53+
* Registers success and error notices for the Form Entries screen, to be displayed
54+
* depending on the action.
55+
*
56+
* @since 3.0.0
57+
*
58+
* @param array $notices Regsitered success and error notices.
59+
* @return array
60+
*/
61+
public function register_notices( $notices ) {
62+
63+
return array_merge(
64+
$notices,
65+
array(
66+
'form_entries_deleted_success' => __( 'Form Entries deleted successfully.', 'convertkit' ),
67+
)
68+
);
69+
70+
}
71+
4772
/**
4873
* Register fields for this section
4974
*
@@ -92,6 +117,13 @@ public function documentation_url() {
92117
*/
93118
public function render() {
94119

120+
/**
121+
* Performs actions prior to rendering the settings form.
122+
*
123+
* @since 3.0.0
124+
*/
125+
do_action( 'convertkit_settings_base_render_before' );
126+
95127
$form_entries = new ConvertKit_Form_Entries();
96128

97129
// Render opening container.
@@ -103,9 +135,14 @@ public function render() {
103135
$this->print_section_info();
104136

105137
// Setup WP_List_Table.
106-
$table = new ConvertKit_WP_List_Table();
138+
$table = new ConvertKit_WP_List_Table( '_wp_convertkit_settings', $this->name );
139+
140+
// Add bulk actions to table.
141+
$table->add_bulk_action( 'export', __( 'Export', 'convertkit' ) );
142+
$table->add_bulk_action( 'delete', __( 'Delete', 'convertkit' ) );
107143

108144
// Add columns to table.
145+
$table->add_column( 'cb', __( 'Select', 'convertkit' ), false );
109146
$table->add_column( 'post_id', __( 'Post ID', 'convertkit' ), false );
110147
$table->add_column( 'first_name', __( 'First Name', 'convertkit' ), false );
111148
$table->add_column( 'email', __( 'Email', 'convertkit' ), false );
@@ -128,16 +165,31 @@ public function render() {
128165
$table->add_items( $entries );
129166

130167
// Set total entries and items per page options key.
131-
$table->set_total_items( $form_entries->total() );
168+
$table->set_total_items( $form_entries->total( $table->get_search() ) );
132169
$table->set_items_per_page_screen_options_key( 'convertkit_form_entries_per_page' );
133170

171+
// Display search term.
172+
if ( $table->is_search() ) {
173+
?>
174+
<span class="subtitle left"><?php esc_html_e( 'Search results for', 'convertkit' ); ?> &quot;<?php echo esc_html( $table->get_search() ); ?>&quot;</span>
175+
<?php
176+
}
177+
134178
// Prepare and display WP_List_Table.
135179
$table->prepare_items();
180+
$table->search_box( __( 'Search', 'convertkit' ), 'convertkit-search' );
136181
$table->display();
137182

138183
// Render closing container.
139184
$this->render_container_end();
140185

186+
/**
187+
* Performs actions after rendering of the settings form.
188+
*
189+
* @since 3.0.0
190+
*/
191+
do_action( 'convertkit_settings_base_render_after' );
192+
141193
}
142194

143195
/**
@@ -180,6 +232,101 @@ public function set_screen_options( $screen_option, $option, $value ) { // phpcs
180232

181233
}
182234

235+
/**
236+
* Runs the bulk actions for the Form Entries table.
237+
*
238+
* @since 3.0.0
239+
*/
240+
public function run_bulk_actions() {
241+
242+
// Bail if nonce is not valid.
243+
if ( ! isset( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'bulk-convertkit-items' ) ) {
244+
return;
245+
}
246+
247+
// Bail if no bulk action is set.
248+
$bulk_action = isset( $_REQUEST['action'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['action'] ) ) : '';
249+
if ( empty( $bulk_action ) ) {
250+
return;
251+
}
252+
253+
// Bail if no entries are selected.
254+
if ( ! isset( $_REQUEST['convertkit-items'] ) ) {
255+
return;
256+
}
257+
258+
// Initialize Form Entries class.
259+
$form_entries = new ConvertKit_Form_Entries();
260+
261+
switch ( $bulk_action ) {
262+
case 'export':
263+
// Get entries.
264+
$ids = array_unique( array_map( 'absint', $_REQUEST['convertkit-items'] ) );
265+
$entries = $form_entries->get_by_ids( $ids );
266+
267+
// Convert entries to CSV string.
268+
$csv = $form_entries->get_csv_string( $entries );
269+
270+
// Force download with output.
271+
header( 'Content-type: application/x-msdownload' );
272+
header( 'Content-Disposition: attachment; filename=kit-form-entries-export.csv' );
273+
header( 'Pragma: no-cache' );
274+
header( 'Expires: 0' );
275+
echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput
276+
exit();
277+
278+
case 'delete':
279+
// Delete entries by IDs.
280+
$ids = array_unique( array_map( 'absint', $_REQUEST['convertkit-items'] ) );
281+
$form_entries->delete_by_ids( $ids );
282+
283+
// Redirect with success notice.
284+
$this->redirect_with_success_notice( 'form_entries_deleted_success' );
285+
break;
286+
}
287+
288+
}
289+
290+
/**
291+
* Defines the settings form's method to 'get', to mirror how
292+
* WP_List_Table works when performing a search.
293+
*
294+
* @since 3.0.0
295+
*
296+
* @param string $form_method Form method (post|get).
297+
* @param string $active_section Active settings section.
298+
* @return string
299+
*/
300+
public function form_method( $form_method, $active_section ) {
301+
302+
if ( $active_section !== $this->name ) {
303+
return $form_method;
304+
}
305+
306+
return 'get';
307+
308+
}
309+
310+
/**
311+
* Defines the settings form's action URL to match the current screen,
312+
* so the search functionality doesn't load options.php, which doesn't work.
313+
*
314+
* @since 3.0.0
315+
*
316+
* @param string $form_action_url URL.
317+
* @param string $active_section Active settings section.
318+
* @return string
319+
*/
320+
public function form_action_url( $form_action_url, $active_section ) {
321+
322+
if ( $active_section !== $this->name ) {
323+
return $form_action_url;
324+
}
325+
326+
return 'options-general.php';
327+
328+
}
329+
183330
}
184331

185332
// Register Admin Settings section.

0 commit comments

Comments
 (0)