true, 'cx' => true, 'cy' => true, 'r' => true, 'x' => true, 'y' => true, 'rx' => true, 'width' => true, 'height' => true, 'fill' => true, 'opacity' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, ); return array( 'svg' => array( 'class' => true, 'viewbox' => true, 'width' => true, 'height' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'aria-hidden' => true, 'xmlns' => true, ), 'path' => $shape, 'circle' => $shape, 'rect' => $shape, 'span' => array( 'class' => true, 'aria-hidden' => true, 'style' => true, ), 'b' => array( 'class' => true ), 'i' => array( 'class' => true ), 'a' => array( 'class' => true, 'href' => true, ), ); } /** * Tags and attributes of a rendered gallery, for wp_kses(). * * @return array */ function tpika_kses_gallery() { $data = array( 'id' => true, 'class' => true, 'style' => true, 'title' => true, 'role' => true, 'aria-label' => true, 'aria-hidden' => true, 'aria-live' => true, 'aria-pressed' => true, 'data-settings' => true, 'data-filter' => true, 'data-filters' => true, 'data-index' => true, 'data-w' => true, 'data-h' => true, 'data-type' => true, 'data-full' => true, 'data-link' => true, 'data-caption' => true, 'data-color' => true, 'data-text' => true, ); return array_merge( tpika_kses_icons(), array( 'div' => $data, 'figure' => $data, 'figcaption' => $data, 'p' => $data, 'span' => $data, 'a' => $data + array( 'href' => true, 'target' => true, 'rel' => true, ), 'button' => $data + array( 'type' => true ), 'select' => $data, 'option' => $data + array( 'value' => true, 'selected' => true, ), 'img' => $data + array( 'src' => true, 'srcset' => true, 'sizes' => true, 'width' => true, 'height' => true, 'alt' => true, 'loading' => true, 'decoding' => true, ), ) ); } /** * Language fallback: a site in de_CH, de_AT, es_MX … uses the closest bundled translation (de_DE, es_ES …). * Hooked on load_textdomain_mofile and load_script_translation_file. * * @param string|false $file Translation file WordPress is about to load. * @return string|false */ function tpika_locale_fallback_file( $file ) { if ( ! $file || ! is_string( $file ) || file_exists( $file ) ) { return $file; } if ( ! preg_match( '/^3pika-gallery-(([a-z]{2,3})(?:_[A-Za-z0-9_]+)?)((?:-[a-z0-9\-]+)?\.(?:mo|json))$/', basename( $file ), $m ) ) { return $file; } // Variants and closely related languages that have no translation of their own. $related = array( 'pt_AO' => 'pt_PT', 'pt_PT_ao90' => 'pt_PT', 'zh_HK' => 'zh_TW', 'zh_SG' => 'zh_CN', 'ary' => 'ar', 'haz' => 'fa_IR', 'szl' => 'pl_PL', 'dsb' => 'de_DE', 'hsb' => 'de_DE', 'fur' => 'it_IT', 'arg' => 'es_ES', 'sah' => 'ru_RU', 'tah' => 'fr_FR', 'kab' => 'fr_FR', 'snd' => 'ur', 'skr' => 'ur', ); $base = TPIKA_PATH . 'languages/3pika-gallery-'; if ( isset( $related[ $m[1] ] ) && file_exists( $base . $related[ $m[1] ] . $m[3] ) ) { return $base . $related[ $m[1] ] . $m[3]; } if ( file_exists( $base . $m[2] . $m[3] ) ) { return $base . $m[2] . $m[3]; } $found = glob( $base . $m[2] . '_*' . $m[3] ); return $found ? $found[0] : $file; } /** * Get all galleries (WP_Post objects). * * @param array $args Extra WP_Query args. * @return WP_Post[] */ function tpika_get_galleries( $args = array() ) { $query = new WP_Query( wp_parse_args( $args, array( 'post_type' => TPIKA_Post_Type::TYPE, 'post_status' => array( 'publish', 'draft' ), 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', 'no_found_rows' => true, ) ) ); return $query->posts; } /** * id => title list for pickers. * * @return array */ function tpika_gallery_options() { $out = array(); foreach ( tpika_get_galleries() as $post ) { /* translators: %d: gallery ID */ $out[ $post->ID ] = $post->post_title ? $post->post_title : sprintf( __( 'Gallery #%d', '3pika-gallery' ), $post->ID ); } return $out; } /** * Shortcode string for a gallery. * * @param int $id Gallery ID. * @return string */ function tpika_shortcode( $id ) { return '[3pika_gallery id="' . absint( $id ) . '"]'; } /** * Render a gallery (template tag). The markup is escaped and ready to print. * * @param int $id Gallery ID. * @param array $args Overrides. * @return string */ function tpika_render( $id, $args = array() ) { $html = wp_kses( TPIKA_Renderer::render( $id, $args ), tpika_kses_gallery() ); return $html; } /** * Admin URL helper. * * @param string $page Page slug. * @param array $args Query args. * @return string */ function tpika_admin_url( $page, $args = array() ) { return add_query_arg( array_merge( array( 'page' => $page ), $args ), admin_url( 'admin.php' ) ); } /** * Preview URL for a gallery (editors only). * * @param int $id Gallery ID. * @return string */ function tpika_preview_url( $id ) { $id = absint( $id ); return add_query_arg( array( 'tpika_preview' => $id, '_wpnonce' => wp_create_nonce( 'tpika_preview_' . $id ), ), home_url( '/' ) ); } /** * Small inline SVG icon set. * * @param string $name Icon name. * @return string */ function tpika_icon( $name ) { $icons = array( 'close' => '', 'prev' => '', 'next' => '', 'zoom' => '', 'play' => '', 'pause' => '', 'fullscreen' => '', 'share' => '', 'download' => '', 'video' => '', /* ---- admin UI (18px, stroke) ---- */ 'images' => '', 'plus' => '', 'film' => '', 'copy' => '', 'edit' => '', 'trash' => '', 'eye' => '', 'duplicate' => '', 'export' => '', 'import' => '', 'settings' => '', 'key' => '', 'check' => '', 'minus' => '', 'grid' => '', 'back' => '', 'drag' => '', 'tag' => '', 'layout' => '', 'lightbox' => '', 'pages' => '', 'shield' => '', 'code' => '', 'sliders' => '', 'star' => '', 'external' => '', 'spark' => '', 'lock' => '', 'unlock' => '', /* ---- hover icons (front-end, 22px stroke) ---- */ 'hi-zoom' => '', 'hi-plus' => '', 'hi-expand' => '', 'hi-eye' => '', 'hi-link' => '', ); return isset( $icons[ $name ] ) ? $icons[ $name ] : ''; } /** * Readable text colour (black or white) for a background colour. * * @param string $hex Background colour (#rrggbb). * @return string */ function tpika_contrast_color( $hex ) { $hex = ltrim( (string) $hex, '#' ); if ( 3 === strlen( $hex ) ) { $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2]; } if ( 6 !== strlen( $hex ) || ! ctype_xdigit( $hex ) ) { return '#ffffff'; } $r = hexdec( substr( $hex, 0, 2 ) ); $g = hexdec( substr( $hex, 2, 2 ) ); $b = hexdec( substr( $hex, 4, 2 ) ); $l = ( 0.299 * $r + 0.587 * $g + 0.114 * $b ) / 255; return $l > 0.6 ? '#111111' : '#ffffff'; } /** * Thumbnail URLs of the first items of a gallery (admin cards). * * @param int $id Gallery ID. * @param int $limit Max thumbs. * @return string[] */ function tpika_gallery_thumbs( $id, $limit = 4 ) { $images = get_post_meta( $id, '_tpika_images', true ); $out = array(); if ( ! is_array( $images ) ) { return $out; } foreach ( $images as $img ) { if ( count( $out ) >= $limit ) { break; } $src = ''; if ( ! empty( $img['id'] ) ) { $s = wp_get_attachment_image_src( (int) $img['id'], 'medium' ); $src = $s ? $s[0] : ''; } if ( $src ) { $out[] = $src; } } return $out; } /** * Icons for the settings sections (nav). * * @param string $slug Section slug. * @return string */ function tpika_section_icon( $slug ) { $map = array( 'layout' => 'layout', 'filters' => 'tag', 'lightbox' => 'lightbox', 'pagination' => 'pages', 'protection' => 'shield', 'advanced' => 'code', 'general' => 'sliders', ); return tpika_icon( isset( $map[ $slug ] ) ? $map[ $slug ] : 'settings' ); }