JFIF $ d d 7 * Z qn )ZP 0 !1 A "#a$2Qr D8 a Ri [f \m I ykI w0 c u F c Rı?lO7 к _f˓ [C $殷WF< _W ԣ s Kc ëI zyQy /_LK ℂ ;C",p F A : /] =H ~ , l s / 9 ć: [=/#f ; ) x { ٛE Q )~ = 𘙲r*2~ a _V = ' ku m F D } KYYC )( { * g& f `툪 r y ` = ^ c J. I ]( * `wq 1dđ #̩ ͑ 0 ; H ] u 搂 @:~ ו K L N s h } O I R* 8 :2 ! lD JV o ( 3 = M ( z Ȱ+i *N A r6K n S l ) ! J J Ӂ* % ݉?|D } d5: eP0 R; {$X' x F @ .ÊB {,WJ uQ ɲRI ;9 Q E琯 6 2fT .DU J ;*c P A\IL Nj! J ۱+ O\ ͔ ] ޒ S J ȧ c%A N ol ՎprU L Zԛe r E2= X D Xg VQeӓ k y P7 U* o m Q I s ,K `) 6\G3t?pgjr m ۛجw luGt f h 9uyP 0D;Uڽ"OXl i f $ ) &|ML 0 Z rm1 [ H XP l P R0 'G=i 2N +0 e 2 ]] 9 VT P O 7 h(F * 癈 ' = Q VZD F,d ߬ ~ T X G[ `le 69C R(!S2! P < 0 x < !1AQ "Raq 02Br #S CTb ? Ζ "]mH5WR 7 k.ۛ ! } Q~ + yԏ z |@ T20 S~ K e k *zF f^2X *( @ 8 r ? C I uI|֓>^Ex LgNU Y+{.R Ѫ τV YT D I 6 2 '8Y2 7'\T P.6 d &˦ @V q i |8 -O Ε ] ʔ U= T L 8= ;6c | !qfF3 a ů& ~$ l} 'NW U s$U k^S V : U#6w + +s &r+n ڐ { @ 29gL u " T Ù M=6 (^ "7 r}=6Yݾ lC u hquymp Ǧ G jhs ǜNl ɻ} o 7 #S6 a w 4 ! OS r D 5 7 % | ?x> L | / nD 6?/8 w # [ ) L 7 +6〼T A T g ! %5 Mm Z /c -{1_Je "| ^$ 'O & ޱմ < H vNqϡQ$ < 6 &Nݛ ֨tǻN (9 n ru~'όN sMG& ,uH Kw *Ī 5@ u6 BԒ i YN * f 0 _ GhKW u lT <nj- 0{ M L~ | /a v\ E = ?1 \ɟuq Ђ Y O a K ޡP q $ H8o Q˼EV ~ k 0 h' L Pp M -M" m^ !6l nմ 쮝C U T . ! :vMǨb h ډ Vc r @~p # !1QAa q ? AL0L x LU 4 d ; x " 16ad0 7.\ߋ 0 = P l v/ " c A Ay A|2pO8"d MV #1] = \ " ˡ ] k v I9 d ۓ & q ) ǐq E ꞅ v "P )q X &Q З non]я u ג./ ; gZ$ M QР 2M ]h ni 0 P $ێ 3CɏGjώy : m c # S_ l@ '_ \m|C 2`K _ 1 cIvGc $? PCQ S+D ? K aײ k Fr b 8 ύ NEدg ĝ U 3 6 #Ik+ v { v i ( ވ ? a e) X xy/*@Q Ǽ Ծ ) $ IWO l c G; !i k{ gOŀ L ('x T rb $ w) R $ & N1E td U3Uȉ1p M"N* (DNy d96.(jQ) X 5 c QɎMy W ? Q *!R > 6=7)Xj 5`J ] e 8%t ! + ' ! 1Q 5 !1 AQaq ё #2 "0BRb ? G t^ ## .l lQ T $ v , ,m 㵜5u bV =sY+ @d { N ! dn O < .- B; _w J t 6;Q Jd. Q c%p{ 1 ,sND dF H I0 Гo X ш e黅X ۢ F :)[ F G X ƹ / w _c MeD ,ʡc c . W D tA $ j@ : ) - #u c1< @ۗ9F ) KJ- hpP] _ x [ q B lb p ʖ w q " LFGd ƶ * s +ډ_Zc " ? % t[I P 6 J ]# =ɺ V v v CGs Gh1 > )6 |e y ? L ӣ m,4 G W Ui ` ] uJVo VDG< SB 6ϏQ @ TiU l y O U 0 kfV ~ ~}S Z @ *WU Ui ## ; s /[ = ! 7}" W N ] ' (L ! ~ y5 g9T̅J kbM' +s :S +B) v @ M j e C f j E 0 Y\Qn z G 1 д~ W o{T 9?` Rm yhsy3 !HAD ] m c1 ~ 2 L S u7x T ;j$ `} 4-> L# vzŏ I L S ֭ T { r jGK C ; b pU= - ` Bs K. S F w4 M q] Z dH S 0 ) tLg
<?php
namespace WPForms\Admin\Forms;
use WP_Post;
/**
* List table views.
*
* @since 1.7.3
*/
class Views {
/**
* Current view slug.
*
* @since 1.7.3
*
* @var string
*/
private $current_view;
/**
* Views settings.
*
* @since 1.7.3
*
* @var array
*/
private $views;
/**
* Count forms in different views.
*
* @since 1.7.3
*
* @var array
*/
private $count;
/**
* Base URL.
*
* @since 1.7.3
*
* @var string
*/
private $base_url;
/**
* Show form templates.
*
* @since 1.8.8
*
* @var bool
*/
private $show_form_templates;
/**
* Views configuration.
*
* @since 1.7.3
*/
private function configuration() {
if ( ! empty( $this->views ) ) {
return;
}
// Define views.
$views = [
'all' => [
'title' => __( 'All', 'wpforms-lite' ),
'get_var' => '',
'get_var_value' => '',
],
'trash' => [
'title' => __( 'Trash', 'wpforms-lite' ),
'get_var' => 'status',
'get_var_value' => 'trash',
'args' => [
'post_status' => 'trash',
],
],
];
$this->show_form_templates = wpforms()->obj( 'forms_overview' )->overview_show_form_templates();
// Add Forms and Templates views if Show Templates setting is enabled.
if ( $this->show_form_templates ) {
$views = wpforms_array_insert(
$views,
[
'forms' => [
'title' => __( 'Forms', 'wpforms-lite' ),
'get_var' => 'type',
'get_var_value' => 'form',
'args' => [
'post_type' => 'wpforms',
],
],
'templates' => [
'title' => __( 'Templates', 'wpforms-lite' ),
'get_var' => 'type',
'get_var_value' => 'template',
'args' => [
'post_type' => 'wpforms-template',
],
],
],
'all'
);
}
// phpcs:disable WPForms.Comments.ParamTagHooks.InvalidParamTagsQuantity
/**
* Filters configuration of the Forms Overview table views.
*
* @since 1.7.3
*
* @param array $views {
* Views array.
*
* @param array $view {
* Each view is the array with three elements:
*
* @param string $title View title.
* @param string $get_var URL query variable name.
* @param string $get_var_value URL query variable value.
* @param array $args Additional arguments to be passed to `wpforms()->obj( 'form' )->get()` method.
* }
* ...
* }
*/
$this->views = apply_filters( 'wpforms_admin_forms_views_configuration', $views );
// phpcs:enable WPForms.Comments.ParamTagHooks.InvalidParamTagsQuantity
}
/**
* Determine if the class is allowed to load.
*
* @since 1.7.3
*
* @return bool
*/
private function allow_load(): bool {
// Load only on the `All Forms` admin page.
return wpforms_is_admin_page( 'overview' );
}
/**
* Initialize class.
*
* @since 1.7.3
*/
public function init() {
if ( ! $this->allow_load() ) {
return;
}
$this->configuration();
$this->update_current_view();
$this->update_base_url();
$this->hooks();
}
/**
* Hooks.
*
* @since 1.7.3
*/
private function hooks() {
add_filter( 'wpforms_overview_table_update_count', [ $this, 'update_count' ], 10, 2 );
add_filter( 'wpforms_overview_table_update_count_all', [ $this, 'update_count' ], 10, 2 );
add_filter( 'wpforms_overview_table_prepare_items_args', [ $this, 'prepare_items_args' ], 100 );
add_filter( 'wpforms_overview_row_actions', [ $this, 'row_actions_all' ], 9, 2 );
add_filter( 'wpforms_overview_row_actions', [ $this, 'row_actions_trash' ], PHP_INT_MAX, 2 );
add_filter( 'wpforms_admin_forms_search_search_reset_block_message', [ $this, 'search_reset_message' ], 10, 4 );
}
/**
* Determine and save current view slug.
*
* @since 1.7.3
*/
private function update_current_view() {
if ( ! is_array( $this->views ) ) {
return;
}
$this->current_view = 'all';
foreach ( $this->views as $slug => $view ) {
if (
// phpcs:disable WordPress.Security.NonceVerification.Recommended
isset( $_GET[ $view['get_var'] ] ) &&
$view['get_var_value'] === sanitize_key( $_GET[ $view['get_var'] ] )
// phpcs:enable WordPress.Security.NonceVerification.Recommended
) {
$this->current_view = $slug;
return;
}
}
}
/**
* Update Base URL.
*
* @since 1.7.3
*/
private function update_base_url() {
if ( ! is_array( $this->views ) ) {
return;
}
$get_vars = wp_list_pluck( $this->views, 'get_var' );
$get_vars = array_merge(
$get_vars,
[
'paged',
'trashed',
'restored',
'deleted',
'duplicated',
]
);
$this->base_url = remove_query_arg( $get_vars );
}
/**
* Get current view slug.
*
* @since 1.7.3
*
* @return string
*/
public function get_current_view(): string {
return $this->current_view;
}
/**
* Get base URL.
*
* @since 1.7.5
*
* @return string
*/
public function get_base_url(): string {
return $this->base_url;
}
/**
* Get view configuration by slug.
*
* @since 1.7.5
*
* @param string $slug View slug.
*
* @return array
*/
public function get_view_by_slug( string $slug ): array {
return $this->views[ $slug ] ?? []; // phpcs:ignore WPForms.Formatting.EmptyLineBeforeReturn.RemoveEmptyLineBeforeReturnStatement
}
/**
* Update count.
*
* @since 1.7.3
*
* @param array $count Number of forms in different views.
* @param array $args Get forms arguments.
*
* @return array
*/
public function update_count( $count, $args ) {
$defaults = [
'nopaging' => true,
'no_found_rows' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'fields' => 'ids',
'post_status' => 'publish',
'post_type' => wpforms()->obj( 'form' )::POST_TYPES,
];
$args = array_merge( $args, $defaults );
$count['all'] = $this->get_all_items_count( $args );
$count['trash'] = $this->get_trashed_forms_count( $args );
// Count forms and templates separately only if Show Templates screen setting is enabled.
if ( $this->show_form_templates ) {
$count['forms'] = $this->get_forms_count( $args );
$count['templates'] = $this->get_form_templates_count( $args );
}
// Store in class property for further use.
$this->count = $count;
return $count;
}
/**
* Get count of all items.
*
* May include only forms or both forms and form templates, depending on the
* Screen Options settings whether to show form templates or not.
*
* @since 1.8.8
*
* @param array $args Get forms arguments.
*
* @return int Number of forms and templates.
*/
private function get_all_items_count( array $args ): int {
if ( ! $this->show_form_templates ) {
$args['post_type'] = 'wpforms';
}
$all_items = wpforms()->obj( 'form' )->get( '', $args );
return is_array( $all_items ) ? count( $all_items ) : 0;
}
/**
* Get count of forms.
*
* @since 1.8.8
*
* @param array $args Get forms arguments.
*
* @return int Number of published forms.
*/
private function get_forms_count( array $args ): int {
$args['post_type'] = 'wpforms';
$forms = wpforms()->obj( 'form' )->get( '', $args );
return is_array( $forms ) ? count( $forms ) : 0;
}
/**
* Get count of form templates.
*
* @since 1.8.8
*
* @param array $args Get forms arguments.
*
* @return int Number of published templates.
*/
private function get_form_templates_count( array $args ): int {
$args['post_type'] = 'wpforms-template';
$templates = wpforms()->obj( 'form' )->get( '', $args );
return is_array( $templates ) ? count( $templates ) : 0;
}
/**
* Get count of trashed items.
*
* May include only forms or both forms and form templates, depending on the
* Screen Options settings whether to show form templates or not.
*
* @since 1.8.8
*
* @param array $args Get forms arguments.
*
* @return int Number of trashed forms.
*/
private function get_trashed_forms_count( array $args ): int {
if ( ! $this->show_form_templates ) {
$args['post_type'] = 'wpforms';
}
$args['post_status'] = 'trash';
$forms = wpforms()->obj( 'form' )->get( '', $args );
return is_array( $forms ) ? count( $forms ) : 0;
}
/**
* Get counts of forms in different views.
*
* @since 1.7.3
*
* @return array
*/
public function get_count(): array {
return $this->count;
}
/**
* Prepare items arguments for list table.
*
* @since 1.8.8
*
* @param array $args Get multiple forms arguments.
*
* @return array
*/
public function prepare_items_args( $args ): array {
$view_args = $this->views[ $this->current_view ]['args'] ?? [];
if ( ! empty( $view_args ) ) {
$args = array_merge( $args, $view_args );
}
return $args;
}
/**
* Get forms from Trash when preparing items for list table.
*
* @since 1.7.3
*
* @depecated 1.8.8 The `prepare_items_args()` now handles all cases, uses `$this->views`.
*
* @param array $args Get multiple forms arguments.
*
* @return array
*/
public function prepare_items_trash( $args ) {
_deprecated_function( __METHOD__, '1.8.8 of the WPForms plugin' );
return $args;
}
/**
* Generate views items.
*
* @since 1.7.3
*
* @return array
*/
public function get_views(): array {
if ( ! is_array( $this->views ) ) {
return [];
}
$views = [];
foreach ( $this->views as $slug => $view ) {
if (
$slug === 'trash' &&
$this->current_view !== 'trash' &&
empty( $this->count[ $slug ] )
) {
continue;
}
$views[ $slug ] = $this->get_view_markup( $slug );
}
/**
* Filters the Forms Overview table views links.
*
* @since 1.7.3
*
* @param array $views Views links.
* @param array $count Count forms in different views.
*/
return apply_filters( 'wpforms_admin_forms_views_get_views', $views, $this->count );
}
/**
* Generate single view item.
*
* @since 1.7.3
*
* @param string $slug View slug.
*
* @return string
*/
private function get_view_markup( string $slug ): string {
if ( empty( $this->views[ $slug ] ) ) {
return '';
}
$view = $this->views[ $slug ];
return sprintf(
'<a href="%1$s"%2$s>%3$s <span class="count">(%4$d)</span></a>',
$slug === 'all' ? esc_url( $this->base_url ) : esc_url( add_query_arg( $view['get_var'], $view['get_var_value'], $this->base_url ) ),
$this->current_view === $slug ? ' class="current"' : '',
esc_html( $view['title'] ),
empty( $this->count[ $slug ] ) ? 0 : absint( $this->count[ $slug ] )
);
}
/**
* Row actions for views "All", "Forms", "Templates".
*
* @since 1.7.3
*
* @param array $row_actions Row actions.
* @param WP_Post $form Form object.
*
* @return array
*/
public function row_actions_all( $row_actions, $form ) { // phpcs:ignore Generic.Metrics.CyclomaticComplexity.TooHigh
// Modify row actions only for these views.
$allowed_views = [ 'all', 'forms', 'templates' ];
if ( ! in_array( $this->current_view, $allowed_views, true ) ) {
return $row_actions;
}
$is_form_template = wpforms_is_form_template( $form );
$row_actions = [];
// Edit.
if ( wpforms_current_user_can( 'edit_form_single', $form->ID ) ) {
$row_actions['edit'] = sprintf(
'<a href="%s" title="%s">%s</a>',
esc_url(
add_query_arg(
[
'view' => 'fields',
'form_id' => $form->ID,
],
admin_url( 'admin.php?page=wpforms-builder' )
)
),
$is_form_template ? esc_attr__( 'Edit this template', 'wpforms-lite' ) : esc_attr__( 'Edit this form', 'wpforms-lite' ),
esc_html__( 'Edit', 'wpforms-lite' )
);
}
// Entries.
if ( wpforms_current_user_can( 'view_entries_form_single', $form->ID ) ) {
$row_actions['entries'] = sprintf(
'<a href="%s" title="%s">%s</a>',
esc_url(
add_query_arg(
[
'view' => 'list',
'form_id' => $form->ID,
],
admin_url( 'admin.php?page=wpforms-entries' )
)
),
esc_attr__( 'View entries', 'wpforms-lite' ),
esc_html__( 'Entries', 'wpforms-lite' )
);
}
// Payments.
if (
wpforms_current_user_can( wpforms_get_capability_manage_options(), $form->ID ) &&
wpforms()->obj( 'payment' )->get_by( 'form_id', $form->ID )
) {
$row_actions['payments'] = sprintf(
'<a href="%s" title="%s">%s</a>',
esc_url(
add_query_arg(
[
'page' => 'wpforms-payments',
'form_id' => $form->ID,
],
admin_url( 'admin.php' )
)
),
esc_attr__( 'View payments', 'wpforms-lite' ),
esc_html__( 'Payments', 'wpforms-lite' )
);
}
// Preview.
if ( wpforms_current_user_can( 'view_form_single', $form->ID ) ) {
$row_actions['preview_'] = sprintf(
'<a href="%s" title="%s" target="_blank" rel="noopener noreferrer">%s</a>',
esc_url( wpforms_get_form_preview_url( $form->ID ) ),
esc_attr__( 'View preview', 'wpforms-lite' ),
esc_html__( 'Preview', 'wpforms-lite' )
);
}
// Duplicate.
if ( wpforms_current_user_can( 'create_forms' ) && wpforms_current_user_can( 'view_form_single', $form->ID ) ) {
$row_actions['duplicate'] = sprintf(
'<a href="%1$s" title="%2$s" data-type="%3$s">%4$s</a>',
esc_url(
wp_nonce_url(
add_query_arg(
[
'action' => 'duplicate',
'form_id' => $form->ID,
],
$this->base_url
),
'wpforms_duplicate_form_nonce'
)
),
$is_form_template ? esc_attr__( 'Duplicate this template', 'wpforms-lite' ) : esc_attr__( 'Duplicate this form', 'wpforms-lite' ),
$is_form_template ? 'template' : 'form',
esc_html__( 'Duplicate', 'wpforms-lite' )
);
}
// Trash.
if ( wpforms_current_user_can( 'delete_form_single', $form->ID ) ) {
$query_arg = [
'action' => 'trash',
'form_id' => $form->ID,
];
if ( $this->current_view !== 'all' ) {
$query_arg['type'] = $this->current_view === 'templates' ? 'template' : 'form';
}
$row_actions['trash'] = sprintf(
'<a href="%s" title="%s">%s</a>',
esc_url(
wp_nonce_url(
add_query_arg( $query_arg, $this->base_url ),
'wpforms_trash_form_nonce'
)
),
$is_form_template ? esc_attr__( 'Move this form template to trash', 'wpforms-lite' ) : esc_attr__( 'Move this form to trash', 'wpforms-lite' ),
esc_html__( 'Trash', 'wpforms-lite' )
);
}
return $row_actions;
}
/**
* Row actions for view "Trash".
*
* @since 1.7.3
*
* @param array $row_actions Row actions.
* @param WP_Post $form Form object.
*
* @return array
*/
public function row_actions_trash( $row_actions, $form ) {
if (
$this->current_view !== 'trash' ||
! wpforms_current_user_can( 'delete_form_single', $form->ID )
) {
return $row_actions;
}
$is_form_template = wpforms_is_form_template( $form );
$row_actions = [];
// Restore form.
$row_actions['restore'] = sprintf(
'<a href="%s" title="%s">%s</a>',
esc_url(
wp_nonce_url(
add_query_arg(
[
'action' => 'restore',
'form_id' => $form->ID,
'status' => 'trash',
],
$this->base_url
),
'wpforms_restore_form_nonce'
)
),
$is_form_template ? esc_attr__( 'Restore this template', 'wpforms-lite' ) : esc_attr__( 'Restore this form', 'wpforms-lite' ),
esc_html__( 'Restore', 'wpforms-lite' )
);
// Delete permanently.
$row_actions['delete'] = sprintf(
'<a href="%1$s" title="%2$s" data-type="%3$s">%4$s</a>',
esc_url(
wp_nonce_url(
add_query_arg(
[
'action' => 'delete',
'form_id' => $form->ID,
'status' => 'trash',
],
$this->base_url
),
'wpforms_delete_form_nonce'
)
),
$is_form_template ? esc_attr__( 'Delete this template permanently', 'wpforms-lite' ) : esc_attr__( 'Delete this form permanently', 'wpforms-lite' ),
$is_form_template ? 'template' : 'form',
esc_html__( 'Delete Permanently', 'wpforms-lite' )
);
return $row_actions;
}
/**
* Search reset message.
*
* @since 1.7.3
*
* @param string $message Search reset block message.
* @param string $search_term Search term.
* @param array $count Count forms in different views.
* @param string $current_view Current view.
*
* @return string
*/
public function search_reset_message( $message, $search_term, $count, $current_view ) {
if ( $current_view !== 'trash' ) {
return $message;
}
$count['trash'] = ! empty( $count['trash'] ) ? $count['trash'] : 0;
return sprintf(
wp_kses( /* translators: %1$d - number of forms found in the trash, %2$s - search term. */
_n(
'Found <strong>%1$d form</strong> in <em>the trash</em> containing <em>"%2$s"</em>',
'Found <strong>%1$d forms</strong> in <em>the trash</em> containing <em>"%2$s"</em>',
(int) $count['trash'],
'wpforms-lite'
),
[
'strong' => [],
'em' => [],
]
),
(int) $count['trash'],
esc_html( $search_term )
);
}
/**
* Extra controls to be displayed between bulk actions and pagination.
*
* @since 1.7.3
*
* @param string $which The location of the table navigation: 'top' or 'bottom'.
*/
public function extra_tablenav( $which ) {
if ( ! wpforms_current_user_can( 'delete_form_single' ) ) {
return;
}
if ( $this->current_view !== 'trash' ) {
return;
}
// Preserve current view after applying bulk action.
echo '<input type="hidden" name="status" value="trash">';
// Display Empty Trash button.
printf(
'<a href="%1$s" class="button delete-all">%2$s</a>',
esc_url(
wp_nonce_url(
add_query_arg(
[
'action' => 'empty_trash',
'form_id' => 1, // Technically, `empty_trash` is one of the bulk actions, therefore we need to provide fake form_id to proceed.
'status' => 'trash',
],
$this->base_url
),
'wpforms_empty_trash_form_nonce'
)
),
esc_html__( 'Empty Trash', 'wpforms-lite' )
);
}
}