'grid',
'columns' => 3,
'columns_tablet' => 'auto',
'columns_mobile' => 'auto',
'gap' => 10,
'radius' => 6,
'radius_corners' => '', // "tl tr br bl" when corners are unlinked, '' = all corners = radius
'aspect' => 'square',
'hover' => 'zoom',
'hover_icon' => 'none',
'caption' => 'hover',
'accent' => '#2271b1',
'image_size' => 'large',
'order' => 'custom',
// Lightbox.
'lightbox' => 1,
'lb_counter' => 1,
'lb_caption' => 1,
// Filters.
'filters_show' => 1,
'filter_style' => 'buttons',
'filter_size' => 'md',
'filter_shadow' => 0,
'filter_mobile' => 'wrap',
'filter_align' => 'center',
'filter_all' => 1,
'filter_all_label' => 'All',
'filter_default' => '',
// Pagination.
'pagination' => 'none',
'per_page' => 12,
'loadmore_label' => 'Load more',
// Global only.
'load_assets_global' => 0,
'delete_on_uninstall' => 0,
);
}
/**
* Field schema grouped in sections. Shared by the gallery builder and the global settings page.
*
* @return array
*/
public static function fields() {
$columns = array();
for ( $i = 1; $i <= 6; $i++ ) {
$columns[ $i ] = $i;
}
$columns_auto = array( 'auto' => __( 'Auto (from desktop)', '3pika-gallery' ) ) + $columns;
$sizes = array();
foreach ( get_intermediate_image_sizes() as $size ) {
$sizes[ $size ] = $size;
}
$sizes['full'] = 'full';
return array(
'layout' => array(
'title' => __( 'Layout', '3pika-gallery' ),
'fields' => array(
'layout' => array(
'label' => __( 'Layout type', '3pika-gallery' ),
'type' => 'choice',
'options' => array(
'grid' => __( 'Grid', '3pika-gallery' ),
'mosaic' => __( 'Mosaic', '3pika-gallery' ),
'list' => __( 'List', '3pika-gallery' ),
),
'previews' => array(
'grid' => '',
'mosaic' => '',
'list' => '',
),
),
'columns' => array(
'label' => __( 'Columns (desktop)', '3pika-gallery' ),
'type' => 'select',
'options' => $columns,
'show_if' => 'layout!=justified',
),
'columns_tablet' => array(
'label' => __( 'Columns (tablet, ≤1024px)', '3pika-gallery' ),
'type' => 'select',
'options' => $columns_auto,
'show_if' => 'layout!=justified',
),
'columns_mobile' => array(
'label' => __( 'Columns (mobile, ≤767px)', '3pika-gallery' ),
'type' => 'select',
'options' => array_slice( $columns_auto, 0, 5, true ),
'show_if' => 'layout!=justified',
),
'aspect' => array(
'label' => __( 'Image ratio', '3pika-gallery' ),
'type' => 'select',
'options' => array(
'square' => __( 'Square 1:1', '3pika-gallery' ),
'4-3' => __( 'Landscape 4:3', '3pika-gallery' ),
'3-2' => __( 'Landscape 3:2', '3pika-gallery' ),
'16-9' => __( 'Wide 16:9', '3pika-gallery' ),
'3-4' => __( 'Portrait 3:4', '3pika-gallery' ),
'original' => __( 'Original', '3pika-gallery' ),
),
'show_if' => 'layout=grid',
),
'gap' => array(
'label' => __( 'Gap between images (px)', '3pika-gallery' ),
'type' => 'number',
'min' => 0,
'max' => 60,
),
'radius' => array(
'label' => __( 'Corner radius (px)', '3pika-gallery' ),
'type' => 'radius',
'min' => 0,
'max' => 60,
'desc' => __( 'Click the lock to set each corner separately (top-left, top-right, bottom-right, bottom-left).', '3pika-gallery' ),
),
'radius_corners' => array(
'label' => 'radius_corners',
'type' => 'text',
'hidden' => true,
),
'hover' => array(
'label' => __( 'Hover effect', '3pika-gallery' ),
'type' => 'choice',
'previews' => array(
'none' => '',
'zoom' => '',
'fade' => '',
),
'options' => array(
'none' => __( 'None', '3pika-gallery' ),
'zoom' => __( 'Zoom', '3pika-gallery' ),
'fade' => __( 'Fade', '3pika-gallery' ),
),
),
'hover_icon' => array(
'label' => __( 'Hover icon', '3pika-gallery' ),
'type' => 'choice',
'options' => array(
'none' => __( 'None', '3pika-gallery' ),
'zoom' => __( 'Magnifier', '3pika-gallery' ),
'plus' => __( 'Plus', '3pika-gallery' ),
'expand' => __( 'Expand', '3pika-gallery' ),
'eye' => __( 'Eye', '3pika-gallery' ),
'link' => __( 'Link', '3pika-gallery' ),
),
'previews' => array(
'none' => '–',
'zoom' => '' . tpika_icon( 'hi-zoom' ) . '',
'plus' => '' . tpika_icon( 'hi-plus' ) . '',
'expand' => '' . tpika_icon( 'hi-expand' ) . '',
'eye' => '' . tpika_icon( 'hi-eye' ) . '',
'link' => '' . tpika_icon( 'hi-link' ) . '',
),
'desc' => __( 'Icon shown in the middle of the image on hover.', '3pika-gallery' ),
),
'caption' => array(
'label' => __( 'Caption', '3pika-gallery' ),
'type' => 'select',
'options' => array(
'none' => __( 'Hidden', '3pika-gallery' ),
'hover' => __( 'Show on hover', '3pika-gallery' ),
'below' => __( 'Below image', '3pika-gallery' ),
),
),
'accent' => array(
'label' => __( 'Accent color', '3pika-gallery' ),
'type' => 'color',
'presets' => array( '#0f0f0f', '#2271b1', '#0f8a5f', '#d6f25a', '#e11d48', '#f59e0b', '#7c3aed', '#0891b2', '#64748b', '#ffffff' ),
'desc' => __( 'Used for active filters, pagination and "Load more". Filters without their own color follow this.', '3pika-gallery' ),
),
'image_size' => array(
'label' => __( 'Thumbnail size', '3pika-gallery' ),
'type' => 'select',
'options' => $sizes,
'desc' => __( 'Image size used in the grid. The lightbox always uses the full image.', '3pika-gallery' ),
),
'order' => array(
'label' => __( 'Order', '3pika-gallery' ),
'type' => 'select',
'options' => array(
'custom' => __( 'Custom (drag & drop)', '3pika-gallery' ),
'random' => __( 'Random', '3pika-gallery' ),
'date_desc' => __( 'Upload date – newest first', '3pika-gallery' ),
'date_asc' => __( 'Upload date – oldest first', '3pika-gallery' ),
'caption_asc' => __( 'Caption A → Z', '3pika-gallery' ),
'caption_desc' => __( 'Caption Z → A', '3pika-gallery' ),
'file_asc' => __( 'File name A → Z', '3pika-gallery' ),
'file_desc' => __( 'File name Z → A', '3pika-gallery' ),
),
),
),
),
'filters' => array(
'title' => __( 'Filters', '3pika-gallery' ),
'fields' => array(
'filters_show' => array(
'label' => __( 'Show filter bar', '3pika-gallery' ),
'type' => 'checkbox',
),
'filter_style' => array(
'label' => __( 'Filter style', '3pika-gallery' ),
'type' => 'choice',
'options' => array(
'buttons' => __( 'Buttons', '3pika-gallery' ),
'pills' => __( 'Pills', '3pika-gallery' ),
'square' => __( 'Square', '3pika-gallery' ),
'soft' => __( 'Soft', '3pika-gallery' ),
'outline' => __( 'Outline', '3pika-gallery' ),
'underline' => __( 'Underline', '3pika-gallery' ),
'text' => __( 'Text only', '3pika-gallery' ),
'dropdown' => __( 'Dropdown', '3pika-gallery' ),
),
'previews' => array(
'buttons' => 'AllWebLogo',
'pills' => 'AllWebLogo',
'square' => 'AllWebLogo',
'soft' => 'AllWebLogo',
'outline' => 'AllWebLogo',
'underline' => 'AllWebLogo',
'text' => 'AllWebLogo',
'dropdown' => 'All ▾',
),
'show_if' => 'filters_show=1',
),
'filter_size' => array(
'label' => __( 'Filter size', '3pika-gallery' ),
'type' => 'select',
'options' => array(
'sm' => __( 'Small', '3pika-gallery' ),
'md' => __( 'Medium', '3pika-gallery' ),
'lg' => __( 'Large', '3pika-gallery' ),
),
'show_if' => 'filters_show=1',
),
'filter_shadow' => array(
'label' => __( 'Shadow on active filter', '3pika-gallery' ),
'type' => 'checkbox',
'show_if' => 'filters_show=1&filter_style!=underline&filter_style!=text&filter_style!=dropdown',
),
'filter_mobile' => array(
'label' => __( 'Filters on mobile', '3pika-gallery' ),
'type' => 'choice',
'options' => array(
'wrap' => __( 'Wrap in rows', '3pika-gallery' ),
'scroll' => __( 'One row, swipe', '3pika-gallery' ),
'chips' => __( 'Small chips', '3pika-gallery' ),
'grid2' => __( '2 columns', '3pika-gallery' ),
'stack' => __( 'Full-width list', '3pika-gallery' ),
'dropdown' => __( 'Dropdown', '3pika-gallery' ),
),
'previews' => array(
'wrap' => 'AllWebLogoApps',
'scroll' => 'AllWebLogoAppsPrint',
'chips' => 'AllWebLogoAppsPrint',
'grid2' => 'AllWebLogoApps',
'stack' => 'AllWebLogo',
'dropdown' => 'All ▾',
),
'show_if' => 'filters_show=1',
),
'filter_align' => array(
'label' => __( 'Alignment', '3pika-gallery' ),
'type' => 'select',
'options' => array(
'left' => __( 'Left', '3pika-gallery' ),
'center' => __( 'Center', '3pika-gallery' ),
'right' => __( 'Right', '3pika-gallery' ),
),
'show_if' => 'filters_show=1',
),
'filter_all' => array(
'label' => __( 'Show "All" filter', '3pika-gallery' ),
'type' => 'checkbox',
'show_if' => 'filters_show=1',
),
'filter_all_label' => array(
'label' => __( '"All" label', '3pika-gallery' ),
'type' => 'text',
'show_if' => 'filters_show=1',
),
'filter_default' => array(
'label' => __( 'Active filter on load', '3pika-gallery' ),
'type' => 'filter_select',
'show_if' => 'filters_show=1',
'desc' => __( 'Which filter is selected when the page loads.', '3pika-gallery' ),
),
),
),
'lightbox' => array(
'title' => __( 'Lightbox', '3pika-gallery' ),
'fields' => array(
'lightbox' => array(
'label' => __( 'Open images in lightbox', '3pika-gallery' ),
'type' => 'checkbox',
),
'lb_caption' => array(
'label' => __( 'Show caption', '3pika-gallery' ),
'type' => 'checkbox',
'show_if' => 'lightbox=1',
),
'lb_counter' => array(
'label' => __( 'Show counter (1 / 12)', '3pika-gallery' ),
'type' => 'checkbox',
'show_if' => 'lightbox=1',
),
),
),
'pagination' => array(
'title' => __( 'Pagination', '3pika-gallery' ),
'fields' => array(
'pagination' => array(
'label' => __( 'Type', '3pika-gallery' ),
'type' => 'choice',
'previews' => array(
'none' => '',
'numbers' => '‹123›',
'loadmore' => 'Load more',
),
'options' => array(
'none' => __( 'None (show all)', '3pika-gallery' ),
'numbers' => __( 'Page numbers', '3pika-gallery' ),
'loadmore' => __( '"Load more" button', '3pika-gallery' ),
),
),
'per_page' => array(
'label' => __( 'Items per page', '3pika-gallery' ),
'type' => 'number',
'min' => 1,
'max' => 200,
'show_if' => 'pagination!=none',
),
'loadmore_label' => array(
'label' => __( '"Load more" label', '3pika-gallery' ),
'type' => 'text',
'show_if' => 'pagination=loadmore',
),
),
),
);
}
/**
* Global-only fields (settings page).
*
* @return array
*/
public static function global_fields() {
return array(
'load_assets_global' => array(
'label' => __( 'Always load gallery assets', '3pika-gallery' ),
'type' => 'checkbox',
'desc' => __( 'Enable if galleries are loaded via AJAX (popups, tabs) and do not initialise. Otherwise assets are only loaded on pages that contain a gallery.', '3pika-gallery' ),
),
'delete_on_uninstall' => array(
'label' => __( 'Delete all data on uninstall', '3pika-gallery' ),
'type' => 'checkbox',
'desc' => __( 'Removes all galleries and settings when the plugin is deleted. Images in the Media Library are never deleted.', '3pika-gallery' ),
),
);
}
/**
* Flat map key => field definition.
*
* @return array
*/
public static function flat_fields() {
static $flat = null;
if ( null === $flat ) {
$flat = array();
foreach ( self::fields() as $section ) {
foreach ( $section['fields'] as $key => $field ) {
$flat[ $key ] = $field;
}
}
foreach ( self::global_fields() as $key => $field ) {
$flat[ $key ] = $field;
}
}
return $flat;
}
/**
* Global settings (defaults for new galleries).
*
* @return array
*/
public static function get() {
$saved = get_option( self::OPTION, array() );
if ( ! is_array( $saved ) ) {
$saved = array();
}
return wp_parse_args( $saved, self::defaults() );
}
/**
* Save global settings.
*
* @param array $input Raw input.
*/
public static function update( $input ) {
update_option( self::OPTION, self::sanitize( $input ) );
}
/**
* Sanitize a settings array against the schema. Unknown keys are dropped, missing keys fall back to defaults.
*
* @param array $input Raw input.
* @param array $base Base values for missing keys (defaults to global settings).
* @return array
*/
public static function sanitize( $input, $base = null ) {
$input = is_array( $input ) ? $input : array();
$defaults = self::defaults();
$base = is_array( $base ) ? wp_parse_args( $base, $defaults ) : $defaults;
$out = array();
foreach ( self::flat_fields() as $key => $field ) {
$default = isset( $base[ $key ] ) ? $base[ $key ] : '';
if ( ! array_key_exists( $key, $input ) ) {
$out[ $key ] = $default;
continue;
}
$val = $input[ $key ];
switch ( $field['type'] ) {
case 'checkbox':
$out[ $key ] = ! empty( $val ) && '0' !== $val && 'false' !== $val ? 1 : 0;
break;
case 'radius':
case 'number':
$val = is_numeric( $val ) ? (int) $val : (int) $default;
if ( isset( $field['min'] ) ) {
$val = max( (int) $field['min'], $val );
}
if ( isset( $field['max'] ) ) {
$val = min( (int) $field['max'], $val );
}
$out[ $key ] = $val;
break;
case 'select':
case 'choice':
$val = is_scalar( $val ) ? (string) $val : '';
$out[ $key ] = array_key_exists( $val, $field['options'] ) ? ( is_numeric( $val ) ? (int) $val : $val ) : $default;
break;
case 'color':
$c = sanitize_hex_color( is_scalar( $val ) ? $val : '' );
$out[ $key ] = $c ? $c : $default;
break;
case 'filter_select':
$out[ $key ] = sanitize_key( is_scalar( $val ) ? $val : '' );
break;
default:
$out[ $key ] = sanitize_text_field( is_scalar( $val ) ? $val : '' );
if ( 'radius_corners' === $key && ! preg_match( '/^\d{1,3} \d{1,3} \d{1,3} \d{1,3}$/', $out[ $key ] ) ) {
$out[ $key ] = '';
}
}
}
return $out;
}
/**
* Resolve "auto" responsive columns from desktop columns.
*
* @param array $s Settings.
* @return array [desktop, tablet, mobile]
*/
public static function resolve_columns( $s ) {
$d = max( 1, min( 6, (int) $s['columns'] ) );
$t = 'auto' === $s['columns_tablet'] ? ( $d <= 2 ? $d : (int) ceil( $d / 2 ) ) : max( 1, (int) $s['columns_tablet'] );
$m = 'auto' === $s['columns_mobile'] ? ( $d >= 3 ? 2 : 1 ) : max( 1, (int) $s['columns_mobile'] );
return array( $d, $t, $m );
}
}