PluginProbe
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More / trunk
Formidable Forms – WordPress Form Builder for Contact Forms, Calculators, Quizzes & More vtrunk
6.35 6.34 6.33.1 6.33 6.32.1 6.32 6.31 6.25 6.25.1 6.26 6.26.1 6.27 6.28 6.29 6.3 6.3.1 6.3.2 6.30 6.4 6.4.1 6.4.2 6.5 6.5.1 6.5.2 6.5.3 All 141 releases
← All changes | classes/helpers/FrmFormsListHelper.php +419 -78 6.25.1 → trunk View file →
@@ -3,12 +3,19 @@
3 3 die( 'You are not allowed to call this page directly.' );
4 4 }
5 5
6 6 class FrmFormsListHelper extends FrmListHelper {
7 +
8 + /**
9 + * @var string
10 + */
7 11 public $status = '';
8 12
9 13 public $total_items = 0;
10 14
15 + /**
16 + * @param array $args
17 + */
11 18 public function __construct( $args ) {
12 19 $this->status = self::get_param( array( 'param' => 'form_type' ) );
13 20
14 21 parent::__construct( $args );
@@ -22,19 +29,20 @@
22 29 /**
23 30 * @return void
24 31 */
25 32 public function prepare_items() {
26 - global $wpdb, $per_page, $mode;
33 + global $per_page, $mode;
27 34
28 35 $page = $this->get_pagenum();
29 36 $per_page = $this->get_items_per_page( 'formidable_page_formidable_per_page' );
30 37
31 - $mode = self::get_param(
38 + $mode = self::get_param(
32 39 array(
33 40 'param' => 'mode',
34 41 'default' => 'list',
35 42 )
36 43 );
44 +
37 45 $orderby = self::get_param(
38 46 array(
39 47 'param' => 'orderby',
40 48 'default' => 'name',
@@ -48,9 +56,9 @@
48 56 );
49 57
50 58 FrmAppController::apply_saved_sort_preference( $orderby, $order );
51 59
52 - $start = self::get_param(
60 + $start = self::get_param(
53 61 array(
54 62 'param' => 'start',
55 63 'default' => ( $page - 1 ) * $per_page,
56 64 )
@@ -82,11 +90,13 @@
82 90 'param' => 's',
83 91 'sanitize' => 'sanitize_text_field',
84 92 )
85 93 );
86 - if ( $s != '' ) {
94 +
95 + if ( $s !== '' ) {
87 96 preg_match_all( '/".*?("|$)|((?<=[\\s",+])|^)[^\\s",+]+/', $s, $matches );
88 97 $search_terms = array_map( 'trim', $matches[0] );
98 +
89 99 foreach ( $search_terms as $term ) {
90 100 $s_query[] = array(
91 101 'or' => true,
92 102 'name LIKE' => $term,
@@ -114,16 +124,42 @@
114 124 /**
115 125 * @return void
116 126 */
117 127 public function no_items() {
128 + $s = self::get_param(
129 + array(
130 + 'param' => 's',
131 + 'sanitize' => 'sanitize_text_field',
132 + )
133 + );
134 +
135 + if ( $s !== '' ) {
136 + $current_url = set_url_scheme(
137 + 'http://' . FrmAppHelper::get_server_value( 'HTTP_HOST' ) . FrmAppHelper::get_server_value( 'REQUEST_URI' )
138 + );
139 + $clear_url = remove_query_arg( 's', $current_url );
140 +
141 + echo '<p>';
142 + printf(
143 + /* translators: %1$s: Start link HTML, %2$s: End link HTML */
144 + esc_html__( 'No forms match your search. %1$sClear search%2$s', 'formidable' ),
145 + '<a href="' . esc_url( $clear_url ) . '">',
146 + '</a>'
147 + );
148 + echo '</p>';
149 + return;
150 + }
151 +
118 152 if ( $this->status === 'trash' ) {
119 153 echo '<p>';
120 154 esc_html_e( 'No forms found in the trash.', 'formidable' );
155 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
121 156 ?>
122 157 <a href="<?php echo esc_url( admin_url( 'admin.php?page=formidable' ) ); ?>">
123 158 <?php esc_html_e( 'See all forms.', 'formidable' ); ?>
124 159 </a>
125 160 <?php
161 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
126 162 echo '</p>';
127 163 } else {
128 164 $title = __( 'No Forms Found', 'formidable' );
129 165 include FrmAppHelper::plugin_path() . '/classes/views/frm-forms/_no_forms.php';
@@ -150,8 +186,10 @@
150 186 return $actions;
151 187 }
152 188
153 189 /**
190 + * @param string $which
191 + *
154 192 * @return void
155 193 */
156 194 public function extra_tablenav( $which ) {
157 195 if ( 'top' !== $which ) {
@@ -157,15 +195,19 @@
157 195 if ( 'top' !== $which ) {
158 196 return;
159 197 }
160 198
161 - if ( 'trash' === $this->status && current_user_can( 'frm_delete_forms' ) ) {
162 - ?>
163 - <div class="alignleft actions frm_visible_overflow">
164 - <?php submit_button( __( 'Empty Trash', 'formidable' ), 'apply', 'delete_all', false ); ?>
165 - </div>
166 - <?php
199 + if ( 'trash' !== $this->status || ! current_user_can( 'frm_delete_forms' ) ) {
200 + return;
167 201 }
202 +
203 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
204 + ?>
205 + <div class="alignleft actions frm_visible_overflow">
206 + <?php submit_button( __( 'Empty Trash', 'formidable' ), 'apply', 'delete_all', false ); ?>
207 + </div>
208 + <?php
209 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
168 210 }
169 211
170 212 /**
171 213 * @return array
@@ -192,18 +234,13 @@
192 234 )
193 235 );
194 236
195 237 foreach ( $statuses as $status => $name ) {
238 + $class = $status == $form_type ? ' class="current"' : ''; // phpcs:ignore Universal.Operators.StrictComparisons
196 239
197 - if ( $status == $form_type ) {
198 - $class = ' class="current"';
199 - } else {
200 - $class = '';
201 - }
202 -
203 240 if ( $counts->{$status} || 'draft' !== $status ) {
204 241 /* translators: %1$s: Status, %2$s: Number of items */
205 - $links[ $status ] = '<a href="' . esc_url( '?page=formidable&form_type=' . $status ) . '" ' . $class . '>' . sprintf( __( '%1$s <span class="count">(%2$s)</span>', 'formidable' ), $name, number_format_i18n( $counts->{$status} ) ) . '</a>';
242 + $links[ $status ] = '<a href="' . esc_url( '?page=formidable&form_type=' . $status ) . '" ' . $class . '>' . sprintf( __( '%1$s <span class="count">(%2$s)</span>', 'formidable' ), $name, number_format_i18n( $counts->{$status} ) ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
206 243 }
207 244
208 245 unset( $status, $name );
209 246 }
@@ -211,28 +248,15 @@
211 248 return $links;
212 249 }
213 250
214 251 /**
215 - * @param string $which
216 - * @return void
217 - */
218 - public function pagination( $which ) {
219 - global $mode;
220 -
221 - parent::pagination( $which );
222 -
223 - if ( 'top' === $which ) {
224 - $this->view_switcher( $mode );
225 - }
226 - }
227 -
228 - /**
229 252 * @param stdClass $item
230 253 * @param string $style
254 + *
231 255 * @return string
232 256 */
233 257 public function single_row( $item, $style = '' ) {
234 - global $frm_vars, $mode;
258 + global $mode;
235 259
236 260 // Set up the hover actions for this user
237 261 $actions = array();
238 262 $edit_link = FrmForm::get_edit_link( $item->id );
@@ -239,24 +263,15 @@
239 263
240 264 $this->get_actions( $actions, $item, $edit_link );
241 265
242 266 $action_links = $this->row_actions( $actions );
267 + $checkbox = $this->get_row_checkbox( $item );
268 + $r = '<tr id="item-action-' . absint( $item->id ) . '"' . $style . '>';
243 269
244 - // Set up the checkbox ( because the user is editable, otherwise its empty )
245 - $checkbox = '<input type="checkbox" name="item-action[]" id="cb-item-action-' . absint( $item->id ) . '" value="' . esc_attr( $item->id ) . '" />';
246 - $checkbox_label_text = sprintf(
247 - // translators: Form title
248 - __( 'Select %s', 'formidable' ),
249 - ! empty( $item->name ) ? $item->name : FrmFormsHelper::get_no_title_text()
250 - );
251 -
252 - $checkbox .= '<label for="cb-item-action-' . absint( $item->id ) . '"><span class="screen-reader-text">' . esc_html( $checkbox_label_text ) . '</span></label>';
253 -
254 - $r = '<tr id="item-action-' . absint( $item->id ) . '"' . $style . '>';
255 -
256 270 list( $columns, $hidden ) = $this->get_column_info();
257 271
258 272 $format = 'Y/m/d';
273 +
259 274 if ( 'list' !== $mode ) {
260 275 $format .= ' \<\b\r \/\> g:i:s a';
261 276 }
262 277
@@ -261,12 +276,12 @@
261 276 }
262 277
263 278 foreach ( $columns as $column_name => $column_display_name ) {
264 279 $class = $column_name . ' column-' . $column_name . ( 'name' === $column_name ? ' post-title page-title column-title' : '' );
280 + $style = '';
265 281
266 - $style = '';
267 282 if ( in_array( $column_name, $hidden, true ) ) {
268 - $class .= ' frm_hidden';
283 + $class .= ' hidden';
269 284 }
270 285
271 286 if ( $column_name === 'name' ) {
272 287 $class .= ' column-primary';
@@ -271,11 +286,10 @@
271 286 if ( $column_name === 'name' ) {
272 287 $class .= ' column-primary';
273 288 }
274 289
275 - $class = 'class="' . esc_attr( $class ) . '"';
276 - $data_colname = ' data-colname="' . esc_attr( $column_display_name ) . '"';
277 - $attributes = $class . $style . $data_colname;
290 + $class = 'class="' . esc_attr( $class ) . '"';
291 + $attributes = $class . $style . $this->get_column_data_attr( $column_name, $column_display_name );
278 292
279 293 switch ( $column_name ) {
280 294 case 'cb':
281 295 $r .= '<th scope="row" class="check-column">' . $checkbox . '</th>';
@@ -292,21 +306,9 @@
292 306 $date = gmdate( $format, strtotime( $item->created_at ) );
293 307 $val = '<abbr title="' . esc_attr( gmdate( 'Y/m/d g:i:s A', strtotime( $item->created_at ) ) ) . '">' . $date . '</abbr>';
294 308 break;
295 309 case 'entries':
296 - if ( isset( $item->options['no_save'] ) && $item->options['no_save'] ) {
297 - $val = FrmAppHelper::icon_by_class(
298 - 'frmfont frm_forbid_icon frm_bstooltip',
299 - array(
300 - 'title' => __( 'Saving entries is disabled for this form', 'formidable' ),
301 - 'echo' => false,
302 - )
303 - );
304 - } else {
305 - $text = FrmEntry::getRecordCount( $item->id );
306 - $val = current_user_can( 'frm_view_entries' ) ? '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-entries&form=' . $item->id ) ) . '">' . $text . '</a>' : $text;
307 - unset( $text );
308 - }
310 + $val = $this->get_entries_column_value( $item );
309 311 break;
310 312 default:
311 313 if ( method_exists( $this, 'column_' . $column_name ) ) {
312 314 $val = call_user_func( array( $this, 'column_' . $column_name ), $item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
@@ -320,31 +322,80 @@
320 322 $r .= '</td>';
321 323 }
322 324 unset( $val );
323 325 }//end foreach
324 - $r .= '</tr>';
326 + return $r . '</tr>';
327 + }
325 328
326 - return $r;
329 + /**
330 + * @param string $column_name
331 + * @param string $column_display_name
332 + *
333 + * @return string
334 + */
335 + private function get_column_data_attr( $column_name, $column_display_name ) {
336 + if ( 'settings' === $column_name ) {
337 + return ' data-colname="' . esc_attr( trim( strip_tags( $column_display_name ) ) ) . '"';
338 + }
339 + return ' data-colname="' . esc_attr( $column_display_name ) . '"';
327 340 }
328 341
329 342 /**
343 + * @param object $item
344 + *
345 + * @return string
346 + */
347 + private function get_entries_column_value( $item ) {
348 + if ( ! empty( $item->options['no_save'] ) ) {
349 + return (string) FrmAppHelper::icon_by_class(
350 + 'frmfont frm_forbid_icon frm_bstooltip',
351 + array(
352 + 'title' => __( 'Saving entries is disabled for this form', 'formidable' ),
353 + 'echo' => false,
354 + )
355 + );
356 + }
357 +
358 + $text = intval( FrmEntry::getRecordCount( $item->id ) );
359 + return current_user_can( 'frm_view_entries' ) ? '<a href="' . esc_url( admin_url( 'admin.php?page=formidable-entries&form=' . $item->id ) ) . '">' . $text . '</a>' : (string) $text; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
360 + }
361 +
362 + /**
363 + * @param object $item
364 + *
365 + * @return string
366 + */
367 + private function get_row_checkbox( $item ) {
368 + // Set up the checkbox (because the user is editable, otherwise it's empty).
369 + $checkbox = '<input type="checkbox" name="item-action[]" id="cb-item-action-' . absint( $item->id ) . '" value="' . esc_attr( $item->id ) . '" />';
370 + $checkbox_label_text = sprintf(
371 + // translators: Form title
372 + __( 'Select %s', 'formidable' ),
373 + ! empty( $item->name ) ? $item->name : FrmFormsHelper::get_no_title_text()
374 + );
375 +
376 + return $checkbox . '<label for="cb-item-action-' . absint( $item->id ) . '"><span class="screen-reader-text">' . esc_html( $checkbox_label_text ) . '</span></label>';
377 + }
378 +
379 + /**
330 380 * Get the HTML for the Actions column in the form list.
331 381 * This includes multiple icons for triggering the embed modal, the visual styler, and an active landing page.
332 382 *
333 383 * @since 6.0
384 + * @deprecated 6.32 We moved these actions to other places. This column will show if there is a filter added to the hook.
334 385 *
335 386 * @param stdClass $form
387 + *
336 388 * @return string
337 389 */
338 390 protected function column_shortcode( $form ) {
339 - $val = '<a href="#" class="frm-embed-form" role="button" aria-label="' . esc_attr__( 'Embed Form', 'formidable' ) . '">' . FrmAppHelper::icon_by_class( 'frmfont frm_code_icon', array( 'echo' => false ) ) . '</a>';
391 + $val = '<a href="#" class="frm-embed-form" role="button" aria-label="' . esc_attr__( 'Embed Form', 'formidable' ) . '">' . FrmAppHelper::icon_by_class( 'frmfont frm_code_icon', array( 'echo' => false ) ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
340 392 $val .= $this->column_style( $form );
341 393 $val .= $this->column_views( $form );
342 394 $val = apply_filters( 'frm_form_list_actions', $val, array( 'form' => $form ) );
343 395 // Remove the space hard coded in Landing pages.
344 396 $val = str_replace( '&nbsp;', '', $val );
345 - $val = '<div>' . $val . '</div>';
346 - return $val;
397 + return '<div>' . $val . '</div>';
347 398 }
348 399
349 400 /**
350 401 * Get the HTML for the Style column in the form list.
@@ -351,8 +402,9 @@
351 402 *
352 403 * @since 6.0
353 404 *
354 405 * @param stdClass $form
406 + *
355 407 * @return string
356 408 */
357 409 protected function column_style( $form ) {
358 410 $style_setting = $form->options['custom_style'] ?? '';
@@ -363,8 +415,9 @@
363 415 return '';
364 416 }
365 417
366 418 $style = FrmStylesController::get_form_style( $form );
419 +
367 420 if ( ! $style ) {
368 421 // Do a second pass to avoid null values.
369 422 $frm_style = new FrmStyle( 'default' );
370 423 $style = $frm_style->get_one();
@@ -370,9 +423,9 @@
370 423 $style = $frm_style->get_one();
371 424 }
372 425
373 426 $href = FrmStylesHelper::get_edit_url( $style, $form->id );
374 - return '<a href="' . esc_url( $href ) . '" title="' . esc_attr( $style->post_title ) . '">' . FrmAppHelper::icon_by_class( 'frmfont frm_pallet_icon', array( 'echo' => false ) ) . '</a>';
427 + return '<a href="' . esc_url( $href ) . '" title="' . esc_attr( $style->post_title ) . '">' . FrmAppHelper::icon_by_class( 'frmfont frm_pallet_icon', array( 'echo' => false ) ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
375 428 }
376 429
377 430 /**
378 431 * Generate the HTML for the form Views page.
@@ -379,23 +432,44 @@
379 432 *
380 433 * @since 6.19
381 434 *
382 435 * @param stdClass $form Form object.
436 + *
383 437 * @return string
384 438 */
385 439 protected function column_views( $form ) {
386 440 $attributes = array(
387 441 'href' => admin_url( 'admin.php?page=formidable-views&form=' . absint( $form->id ) . '&show_nav=1' ),
388 - 'title' => __( 'View Form', 'formidable' ),
442 + 'title' => __( 'Link to list of all views for this form.', 'formidable' ),
389 443 'target' => '_blank',
390 444 );
391 445
446 + if ( class_exists( 'FrmViewsDisplay' ) ) {
447 + $view_ids = FrmViewsDisplay::get_display_ids_by_form( $form->id );
448 + $view_count = $view_ids ? count( $view_ids ) : 0;
449 + } else {
450 + $view_count = 0;
451 + }
452 +
453 + // phpcs:disable Generic.WhiteSpace.ScopeIndent
392 454 return '<a ' . FrmAppHelper::array_to_html_params( $attributes ) . '>
393 - ' . FrmAppHelper::icon_by_class( 'frmfont frm_eye_icon', array( 'echo' => false ) ) .
455 + ' . intval( $view_count ) .
394 456 '</a>';
457 + // phpcs:enable Generic.WhiteSpace.ScopeIndent
395 458 }
396 459
397 460 /**
461 + * Get the HTML for the Settings column in the form list.
462 + *
463 + * @since 6.32
464 + *
465 + * @return string
466 + */
467 + protected function column_settings() {
468 + return '&nbsp;';
469 + }
470 +
471 + /**
398 472 * @param array $actions
399 473 * @param object $item
400 474 * @param string $edit_link
401 475 *
@@ -402,8 +476,9 @@
402 476 * @return void
403 477 */
404 478 private function get_actions( &$actions, $item, $edit_link ) {
405 479 $new_actions = FrmFormsHelper::get_action_links( $item->id, $item );
480 +
406 481 foreach ( $new_actions as $link => $action ) {
407 482 $new_actions[ $link ] = FrmFormsHelper::format_link_html( $action, 'short' );
408 483 }
409 484
@@ -412,14 +487,15 @@
412 487 return;
413 488 }
414 489
415 490 if ( current_user_can( 'frm_edit_forms' ) ) {
416 - $actions['frm_edit'] = '<a href="' . esc_url( $edit_link ) . '">' . __( 'Edit', 'formidable' ) . '</a>';
417 - $actions['frm_settings'] = '<a href="' . esc_url( '?page=formidable&frm_action=settings&id=' . $item->id ) . '">' . __( 'Settings', 'formidable' ) . '</a>';
491 + $actions['frm_edit'] = '<a href="' . esc_url( $edit_link ) . '">' . esc_html__( 'Edit', 'formidable' ) . '</a>';
492 + $actions['frm_settings'] = '<a href="' . esc_url( '?page=formidable&frm_action=settings&id=' . $item->id ) . '">' . esc_html__( 'Settings', 'formidable' ) . '</a>';
418 493 }
419 494
420 - $actions = array_merge( $actions, $new_actions );
421 - $actions['view'] = '<a href="' . esc_url( FrmFormsHelper::get_direct_link( $item->form_key, $item ) ) . '" target="_blank">' . __( 'Preview', 'formidable' ) . '</a>';
495 + $actions = array_merge( $actions, $new_actions );
496 + $actions['embed'] = '<a href="#" class="frm-embed-form" role="button" aria-label="' . esc_attr__( 'Embed Form', 'formidable' ) . '">' . esc_html__( 'Embed', 'formidable' ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
497 + $actions['view'] = '<a href="' . esc_url( FrmFormsHelper::get_direct_link( $item->form_key, $item ) ) . '" target="_blank">' . esc_html__( 'Preview', 'formidable' ) . '</a>'; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
422 498 }
423 499
424 500 /**
425 501 * @param object $item
@@ -430,21 +506,25 @@
430 506 * @return string
431 507 */
432 508 private function get_form_name( $item, $actions, $edit_link, $mode = 'list' ) {
433 509 $form_name = $item->name;
434 - if ( is_null( $form_name ) || trim( $form_name ) == '' ) {
510 +
511 + if ( is_null( $form_name ) || trim( $form_name ) === '' ) {
435 512 $form_name = FrmFormsHelper::get_no_title_text();
436 513 }
514 +
437 515 $form_name = FrmAppHelper::kses( $form_name );
438 - if ( 'excerpt' != $mode ) {
516 +
517 + if ( 'excerpt' !== $mode ) {
439 518 $form_name = FrmAppHelper::truncate( $form_name, 50 );
440 519 }
441 520
442 521 $val = '<strong>';
522 +
443 523 if ( 'trash' === $this->status ) {
444 524 $val .= $form_name;
445 525 } else {
446 - $val .= '<a href="' . esc_url( isset( $actions['frm_edit'] ) ? $edit_link : FrmFormsHelper::get_direct_link( $item->form_key, $item ) ) . '" class="row-title">' . FrmAppHelper::kses( $form_name ) . '</a> ';
526 + $val .= '<a href="' . esc_url( isset( $actions['frm_edit'] ) ? $edit_link : FrmFormsHelper::get_direct_link( $item->form_key, $item ) ) . '" class="row-title">' . FrmAppHelper::kses( $form_name ) . '</a> '; // phpcs:ignore SlevomatCodingStandard.Files.LineLength.LineTooLong
447 527 }
448 528
449 529 $this->add_draft_label( $item, $val );
450 530 $val .= '</strong>';
@@ -460,9 +540,9 @@
460 540 *
461 541 * @return void
462 542 */
463 543 private function add_draft_label( $item, &$val ) {
464 - if ( 'draft' === $item->status && 'draft' != $this->status ) {
544 + if ( 'draft' === $item->status && 'draft' !== $this->status ) {
465 545 $val .= ' - <span class="post-state">' . esc_html__( 'Draft', 'formidable' ) . '</span>';
466 546 }
467 547 }
468 548
@@ -473,8 +553,9 @@
473 553 * @return void
474 554 */
475 555 private function add_form_description( $item, &$val ) {
476 556 global $mode;
557 +
477 558 if ( 'excerpt' === $mode && ! is_null( $item->description ) ) {
478 559 $val .= FrmAppHelper::truncate( strip_tags( $item->description ), 50 );
479 560 }
480 561 }
@@ -483,6 +564,266 @@
483 564 * @return string
484 565 */
485 566 protected function confirm_bulk_delete() {
486 567 return __( 'ALL selected forms and their entries will be permanently deleted. Want to proceed?', 'formidable' );
568 + }
569 +
570 + /**
571 + * @param stdClass $form
572 + *
573 + * @return string
574 + */
575 + public function column_embeds( $form ) {
576 + if ( $this->column_is_hidden( 'embeds' ) ) {
577 + // Locating embeds means scanning post_content, so skip it when the column is hidden.
578 + return '';
579 + }
580 +
581 + $posts = $this->get_posts_contain_form( $form );
582 +
583 + if ( ! $posts ) {
584 + return '<span class="frm-forms-list-embeds-zero">0</span>';
585 + }
586 +
587 + return FrmAppHelper::clip(
588 + function () use ( $posts ) {
589 + ?>
590 + <a href="#" class="frm-forms-list-embeds-btn" data-posts="<?php echo esc_attr( wp_json_encode( $posts ) ); ?>">
591 + <?php
592 + FrmAppHelper::icon_by_class( 'frmfont frm_arrowdown6_icon' );
593 + echo intval( count( $posts ) );
594 + ?>
595 + </a>
596 + <?php
597 + }
598 + );
599 + }
600 +
601 + /**
602 + * Checks if a column is hidden with Screen Options.
603 + *
604 + * @since 6.35
605 + *
606 + * @param string $column_name Column name.
607 + *
608 + * @return bool
609 + */
610 + private function column_is_hidden( $column_name ) {
611 + $column_info = $this->get_column_info();
612 +
613 + if ( ! isset( $column_info[1] ) || ! is_array( $column_info[1] ) ) {
614 + return false;
615 + }
616 +
617 + return in_array( $column_name, $column_info[1], true );
618 + }
619 +
620 + /**
621 + * Gets posts or pages that contain the form shortcode.
622 + *
623 + * @since 6.32
624 + *
625 + * @param stdClass $form Form object.
626 + *
627 + * @return array
628 + */
629 + private function get_posts_contain_form( $form ) {
630 + $cached_posts = FrmFormEmbedsHelper::get_cached_posts();
631 +
632 + if ( ! isset( $cached_posts[ $form->id ] ) || ! is_array( $cached_posts[ $form->id ] ) ) {
633 + // A single scan covers every form listed on this page, not just this one.
634 + $cached_posts = $this->fill_embed_posts_cache( $form );
635 + }
636 +
637 + if ( ! isset( $cached_posts[ $form->id ] ) || ! is_array( $cached_posts[ $form->id ] ) ) {
638 + return array();
639 + }
640 +
641 + // Links and title fallbacks are derived at render time, not stored. get_edit_post_link()
642 + // depends on the current user, so caching it in a shared transient would hand one user's
643 + // edit link to another, and a permalink cached now goes stale on any slug change.
644 + return FrmFormEmbedsHelper::prepare_posts( $cached_posts[ $form->id ] );
645 + }
646 +
647 + /**
648 + * Scans for embeds once and caches the result for every form listed on the current page.
649 + *
650 + * @since 6.35
651 + *
652 + * @param stdClass $form The form whose column is currently rendering.
653 + *
654 + * @return array Embed posts keyed by form ID.
655 + */
656 + private function fill_embed_posts_cache( $form ) {
657 + $cached_posts = FrmFormEmbedsHelper::get_cached_posts();
658 + $search_map = array();
659 + $forms = array();
660 +
661 + foreach ( $this->get_forms_to_scan( $form ) as $form_id => $form_to_scan ) {
662 + if ( isset( $cached_posts[ $form_id ] ) && is_array( $cached_posts[ $form_id ] ) ) {
663 + continue;
664 + }
665 +
666 + $search_map[ $form_id ] = $this->get_search_strings_for_form( $form_id );
667 + $forms[ $form_id ] = $form_to_scan;
668 + }
669 +
670 + if ( ! $forms ) {
671 + return $cached_posts;
672 + }
673 +
674 + $matched = FrmFormEmbedsHelper::match_candidate_posts( $search_map );
675 +
676 + foreach ( $forms as $form_id => $form_to_scan ) {
677 + $posts = $this->filter_embed_posts( $matched[ $form_id ], $form_to_scan );
678 + $cached_posts[ $form_id ] = FrmFormEmbedsHelper::slim_posts( $posts );
679 + }
680 +
681 + FrmFormEmbedsHelper::save_cached_posts( $cached_posts );
682 +
683 + return $cached_posts;
684 + }
685 +
686 + /**
687 + * Gets every form rendered on the current list page, keyed by form ID.
688 + *
689 + * @since 6.35
690 + *
691 + * @param stdClass $form The form whose column is currently rendering.
692 + *
693 + * @return array
694 + */
695 + private function get_forms_to_scan( $form ) {
696 + $forms = array( $form->id => $form );
697 +
698 + if ( ! is_array( $this->items ) ) {
699 + return $forms;
700 + }
701 +
702 + foreach ( $this->items as $item ) {
703 + if ( is_object( $item ) && isset( $item->id ) ) {
704 + $forms[ $item->id ] = $item;
705 + }
706 + }
707 +
708 + return $forms;
709 + }
710 +
711 + /**
712 + * Applies the frm_get_posts_contain_form filter to a form's embed posts.
713 + *
714 + * @since 6.35
715 + *
716 + * @param array $posts Posts that embed the form.
717 + * @param stdClass $form Form object.
718 + *
719 + * @return array
720 + */
721 + private function filter_embed_posts( $posts, $form ) {
722 + /**
723 + * @since 6.32
724 + *
725 + * @param stdClass[] $posts
726 + * @param array $args
727 + */
728 + $filtered_posts = apply_filters( 'frm_get_posts_contain_form', $posts, compact( 'form' ) );
729 +
730 + if ( ! is_array( $filtered_posts ) ) {
731 + _doing_it_wrong( 'frm_get_posts_contain_form', 'Filter should return an array.', '6.32' );
732 + return $posts;
733 + }
734 +
735 + return $filtered_posts;
736 + }
737 +
738 + /**
739 + * Gets search strings for a form inside a post.
740 + *
741 + * @since 6.32
742 + *
743 + * @param int $form_id Form ID.
744 + *
745 + * @return string[]
746 + */
747 + protected function get_search_strings_for_form( $form_id ) {
748 + return $this->get_base_search_strings_for_form( $form_id );
749 + }
750 +
751 + /**
752 + * Gets the base search strings for a form inside a post.
753 + *
754 + * @since 6.32
755 + *
756 + * @param int $form_id Form ID.
757 + *
758 + * @return string[]
759 + */
760 + protected function get_base_search_strings_for_form( $form_id ) {
761 + $strings = array(
762 + '<!-- wp:formidable/simple-form {"formId":"' . $form_id . '"',
763 + );
764 +
765 + // The shortcode renders a form from its key just as happily as from its ID, in either
766 + // attribute, so all four spellings have to be searched or those pages never count.
767 + $identifiers = array( $form_id );
768 + $form_key = FrmForm::get_key_by_id( $form_id );
769 +
770 + if ( $form_key && $form_key !== (string) $form_id ) {
771 + $identifiers[] = $form_key;
772 + }
773 +
774 + foreach ( $identifiers as $identifier ) {
775 + foreach ( array( 'id', 'key' ) as $att ) {
776 + $strings[] = '[formidable ' . $att . '=' . $identifier . ']';
777 + $strings[] = '[formidable ' . $att . '=' . $identifier . ' ';
778 + $strings[] = '[formidable ' . $att . '="' . $identifier . '"';
779 + $strings[] = '[formidable ' . $att . "='" . $identifier . "'";
780 + }
781 + }
782 +
783 + return $strings;
784 + }
785 +
786 + /**
787 + * Maybe clear the embed posts transient when a post is inserted.
788 + *
789 + * @since 6.32
790 + *
791 + * @param int $post_id Post ID.
792 + * @param WP_Post $post Post object.
793 + * @param bool $update True when an existing post was updated rather than created.
794 + *
795 + * @return void
796 + */
797 + public static function maybe_clear_embed_posts_transient( $post_id, $post, $update = false ) {
798 + FrmFormEmbedsHelper::maybe_clear_on_insert( $post_id, $post, $update );
799 + }
800 +
801 + /**
802 + * Maybe clear the embed posts transient when a post is updated.
803 + *
804 + * @since 6.35
805 + *
806 + * @param int $post_id Post ID.
807 + * @param WP_Post $post_after Post object after the update.
808 + * @param WP_Post $post_before Post object before the update.
809 + *
810 + * @return void
811 + */
812 + public static function maybe_clear_embed_posts_transient_on_update( $post_id, $post_after, $post_before ) {
813 + FrmFormEmbedsHelper::maybe_clear_on_update( $post_id, $post_after, $post_before );
814 + }
815 +
816 + /**
817 + * Maybe clear the embed posts transient when a post is trashed, untrashed or deleted.
818 + *
819 + * @since 6.35
820 + *
821 + * @param int $post_id Post ID.
822 + * @param WP_Post|null $post Post object, when the hook provides one.
823 + *
824 + * @return void
825 + */
826 + public static function clear_embed_posts_transient_for_post( $post_id, $post = null ) {
827 + FrmFormEmbedsHelper::maybe_clear_for_post( $post_id, $post );
487 828 }
488 829 }