'field',
'plural' => 'fields',
'ajax' => false,
) );
$this->field_types = accua_forms_fields_get_types();
}
function get_columns() {
return array(
'cb' => '',
'name' => __( 'Label', 'contact-forms' ),
'slug' => __( 'Slug', 'contact-forms' ),
'type' => __( 'Type', 'contact-forms' ),
'forms' => __( 'Forms', 'contact-forms' ),
'description' => __( 'Description', 'contact-forms' ),
);
}
function get_sortable_columns() {
return array(
'name' => array( 'name', false ),
'slug' => array( 'slug', false ),
'type' => array( 'type', false ),
'forms' => array( 'forms', false ),
);
}
function get_bulk_actions() {
return array(
'delete' => __( 'Delete', 'contact-forms' ),
);
}
function column_cb( $item ) {
return sprintf(
'',
esc_attr( $item['slug'] )
);
}
function column_default( $item, $column_name ) {
if ( isset( $item[ $column_name ] ) ) {
return esc_html( $item[ $column_name ] );
}
return '';
}
function column_name( $item ) {
$edit_url = admin_url( 'admin.php?page=accua_forms_fields&edit-fid=' . urlencode( $item['slug'] ) );
$delete_url = wp_nonce_url(
admin_url( 'admin.php?page=accua_forms_fields&delete-fid=' . urlencode( $item['slug'] ) ),
'delete_form_field_' . $item['slug']
);
$actions = array(
'edit' => sprintf(
'%s',
esc_url( $edit_url ),
esc_html__( 'Edit', 'contact-forms' )
),
'delete' => sprintf(
'%s',
esc_url( $delete_url ),
esc_js( __( 'Are you sure you want to delete this field?', 'contact-forms' ) ),
esc_html__( 'Delete', 'contact-forms' )
),
);
return sprintf(
'%s%s',
esc_url( $edit_url ),
esc_html( $item['name'] ),
$this->row_actions( $actions )
);
}
function column_type( $item ) {
$type_key = $item['type'];
if ( isset( $this->field_types[ $type_key ] ) ) {
return esc_html( $this->field_types[ $type_key ] );
}
return esc_html( $type_key );
}
function column_forms( $item ) {
$count = $item['forms'];
if ( $count > 0 ) {
return '' . (int) $count . '';
}
return '0';
}
/**
* Whether a row matches the current search.
*
* Searches the text the table actually shows: label, slug, type and
* description. The type is matched on its human-readable label as well as
* its key, so "Casella di controllo" finds a checkbox field on an Italian
* install just as "checkbox" does on an English one.
*/
private function matches_search( $item ) {
$type_label = isset( $this->field_types[ $item['type'] ] ) ? $this->field_types[ $item['type'] ] : '';
$haystack = implode( ' ', array(
$item['name'],
$item['slug'],
$item['type'],
$type_label,
$item['description'],
) );
// mb_stripos keeps the match case-insensitive for accented characters;
// mbstring is not guaranteed to be installed, hence the fallback.
if ( function_exists( 'mb_stripos' ) ) {
return false !== mb_stripos( $haystack, $this->search );
}
return false !== stripos( $haystack, $this->search );
}
function no_items() {
if ( '' !== $this->search ) {
esc_html_e( 'No fields match your search.', 'contact-forms' );
return;
}
esc_html_e( 'No fields found.', 'contact-forms' );
}
function prepare_items() {
$columns = $this->get_columns();
$hidden = array();
$sortable = $this->get_sortable_columns();
$this->_column_headers = array( $columns, $hidden, $sortable );
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only search parameter
$this->search = isset( $_REQUEST['s'] ) ? trim( sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) ) : '';
$avail_fields = get_option( 'accua_forms_avail_fields', array() );
$saved_forms = get_option( 'accua_forms_saved_forms', array() );
// Count how many forms use each field
$field_usage = array();
foreach ( $saved_forms as $form ) {
if ( ! empty( $form['fields'] ) && is_array( $form['fields'] ) ) {
foreach ( array_keys( $form['fields'] ) as $field_slug ) {
if ( ! isset( $field_usage[ $field_slug ] ) ) {
$field_usage[ $field_slug ] = 0;
}
$field_usage[ $field_slug ]++;
}
}
}
$data = array();
foreach ( $avail_fields as $id => $field ) {
$data[] = array(
'slug' => $id,
'name' => $field['name'] ?? $field['label'] ?? $id,
'type' => $field['type'] ?? '',
'forms' => $field_usage[ $id ] ?? 0,
'description' => $field['description'] ?? '',
);
}
// Search first, so the count, the order and the paging are all those of
// the result set rather than of the whole list.
if ( '' !== $this->search ) {
$data = array_values( array_filter( $data, array( $this, 'matches_search' ) ) );
}
// Sorting
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only sort parameter
$orderby = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'slug';
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only sort parameter
$order = isset( $_GET['order'] ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : 'asc';
$valid_columns = array( 'name', 'slug', 'type', 'forms' );
if ( ! in_array( $orderby, $valid_columns, true ) ) {
$orderby = 'slug';
}
$order_asc = ( 'desc' !== strtolower( $order ) );
usort( $data, function ( $a, $b ) use ( $orderby, $order_asc ) {
if ( $orderby === 'forms' ) {
$result = $a['forms'] - $b['forms'];
} else {
$result = strcasecmp( $a[ $orderby ], $b[ $orderby ] );
}
return $order_asc ? $result : -$result;
} );
// Paging. Mostly this is what puts the "N items" count above the table,
// which is the feedback a search needs; the list is short enough on a
// normal install that the page links never appear.
$per_page = $this->get_items_per_page( 'accua_forms_fields_per_page', 50 );
$total_items = count( $data );
$current_page = $this->get_pagenum();
$this->set_pagination_args( array(
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => (int) ceil( $total_items / max( 1, $per_page ) ),
) );
$this->items = array_slice( $data, ( $current_page - 1 ) * $per_page, $per_page );
}
protected function get_default_primary_column_name() {
return 'name';
}
}