array( 'name' => __( 'Events', 'bearius-calendar' ), 'singular_name' => __( 'Event', 'bearius-calendar' ), 'add_new' => __( 'Add event', 'bearius-calendar' ), 'add_new_item' => __( 'Add new event', 'bearius-calendar' ), 'edit_item' => __( 'Edit event', 'bearius-calendar' ), 'new_item' => __( 'New event', 'bearius-calendar' ), 'view_item' => __( 'View event', 'bearius-calendar' ), 'search_items' => __( 'Search events', 'bearius-calendar' ), 'not_found' => __( 'No events found', 'bearius-calendar' ), 'not_found_in_trash' => __( 'No events in trash', 'bearius-calendar' ), 'all_items' => __( 'All events', 'bearius-calendar' ), 'menu_name' => 'Bearius Calendar', ), 'public' => true, 'has_archive' => $s['slug'], 'rewrite' => array( 'slug' => bcal_single_base(), 'with_front' => false, ), 'menu_icon' => 'dashicons-calendar-alt', 'menu_position' => 21, 'supports' => array( 'title', 'editor', 'thumbnail', 'excerpt', 'author', 'revisions', 'custom-fields' ), 'show_in_rest' => true, ) ); $taxonomies = array( 'bcal_category' => array( 'slug' => $s['slug_category'], 'hierarchical' => true, 'name' => __( 'Categories', 'bearius-calendar' ), 'singular' => __( 'Category', 'bearius-calendar' ), 'column' => true, ), 'bcal_city' => array( 'slug' => $s['slug_city'], 'hierarchical' => true, 'name' => __( 'Cities', 'bearius-calendar' ), 'singular' => __( 'City', 'bearius-calendar' ), 'column' => false, 'picker' => true, ), 'bcal_venue' => array( 'slug' => $s['slug_venue'], 'hierarchical' => false, 'name' => __( 'Venues', 'bearius-calendar' ), 'singular' => __( 'Venue', 'bearius-calendar' ), 'column' => false, 'picker' => true, ), 'bcal_organizer' => array( 'slug' => $s['slug_organizer'], 'hierarchical' => false, 'name' => __( 'Organizers', 'bearius-calendar' ), 'singular' => __( 'Organizer', 'bearius-calendar' ), 'column' => false, 'picker' => true, ), ); foreach ( $taxonomies as $taxonomy => $def ) { $picker = ! empty( $def['picker'] ); $args = array( 'labels' => array( 'name' => $def['name'], 'singular_name' => $def['singular'], 'menu_name' => $def['name'], ), 'public' => true, 'hierarchical' => $def['hierarchical'], 'show_admin_column' => $def['column'], 'show_in_rest' => true, 'show_in_quick_edit' => ! $picker, 'rewrite' => array( 'slug' => $def['slug'], 'with_front' => false, 'hierarchical' => $def['hierarchical'], ), ); // Venue, city and organizer are chosen in the "Event details" box. if ( $picker ) { $args['meta_box_cb'] = false; } register_taxonomy( $taxonomy, BCAL_PT, $args ); } foreach ( bcal_meta_keys() as $key => $type ) { if ( 'boolean' === $type ) { $sanitize = 'rest_sanitize_boolean'; } elseif ( in_array( $key, array( 'ticket_url', 'ticket_url_2', 'online_url', 'source_url' ), true ) ) { // Not sanitize_text_field: it strips %XX sequences and breaks affiliate links. $sanitize = 'esc_url_raw'; } else { $sanitize = 'sanitize_text_field'; } register_post_meta( BCAL_PT, '_bcal_' . $key, array( 'type' => $type, 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => $sanitize, 'auth_callback' => function ( $allowed, $meta_key, $post_id ) { return current_user_can( 'edit_post', $post_id ); }, ) ); } register_term_meta( 'bcal_venue', 'bcal_city_id', array( 'type' => 'integer', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'absint', ) ); $term_meta = array( 'bcal_venue' => array( 'bcal_address', 'bcal_postal', 'bcal_lat', 'bcal_lng', 'bcal_aliases' ), 'bcal_organizer' => array( 'bcal_url', 'bcal_aliases' ), 'bcal_city' => array( 'bcal_aliases' ), 'bcal_category' => array( 'bcal_aliases', 'bcal_color' ), ); foreach ( $term_meta as $taxonomy => $keys ) { foreach ( $keys as $key ) { register_term_meta( $taxonomy, $key, array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'bcal_url' === $key ? 'esc_url_raw' : 'sanitize_text_field', ) ); } } } add_action( 'init', 'bcal_register_content_types' ); /** * URL base of single events: its own setting, or the archive base. * * @return string */ function bcal_single_base() { $single = (string) bcal_opt( 'slug_single' ); return '' !== $single ? $single : (string) bcal_opt( 'slug' ); } /** * Dates of recurring events in the path, as used by other calendars * (/event/name/2026-10-05/), redirect to the event page on that date. */ function bcal_occurrence_rewrite() { add_rewrite_tag( '%bcal_occ%', '(\d{4}-\d{2}-\d{2})' ); add_rewrite_rule( '^' . preg_quote( bcal_single_base(), '#' ) . '/([^/]+)/(\d{4}-\d{2}-\d{2})/?$', 'index.php?post_type=' . BCAL_PT . '&name=$matches[1]&bcal_occ=$matches[2]', 'top' ); } add_action( 'init', 'bcal_occurrence_rewrite', 11 ); add_action( 'template_redirect', function () { $date = get_query_var( 'bcal_occ' ); if ( ! $date || ! is_singular( BCAL_PT ) ) { return; } $url = (string) get_permalink( get_queried_object_id() ); if ( $url ) { wp_safe_redirect( add_query_arg( 'bcal_date', $date, $url ), 301 ); exit; } }, 1 ); /** * Block editor: hide the default panels for venue, city and organizer, * they are chosen in the "Event details" box like in the classic editor. * * @param WP_REST_Response $response Response. * @param WP_Taxonomy $taxonomy Taxonomy. * @return WP_REST_Response */ function bcal_hide_picker_panels( $response, $taxonomy ) { if ( in_array( $taxonomy->name, array( 'bcal_venue', 'bcal_city', 'bcal_organizer' ), true ) && isset( $response->data['visibility'] ) ) { $response->data['visibility']['show_ui'] = false; } return $response; } add_filter( 'rest_prepare_taxonomy', 'bcal_hide_picker_panels', 10, 2 ); /** * Flushes rewrite rules once after slugs changed in settings. */ function bcal_maybe_flush_rewrites() { if ( get_option( 'bcal_flush_rewrite' ) ) { delete_option( 'bcal_flush_rewrite' ); flush_rewrite_rules(); } } add_action( 'init', 'bcal_maybe_flush_rewrites', 99 ); /** * Optionally generate only the core sizes the calendar uses for images * uploaded to events. Does not add sizes, it only skips the rest. * * @param array $sizes Sizes to generate. * @param array $metadata Image metadata. * @param int $attachment_id Attachment ID. * @return array */ function bcal_limit_image_sizes( $sizes, $metadata = array(), $attachment_id = 0 ) { if ( ! bcal_opt( 'limit_image_sizes' ) ) { return $sizes; } $parent = $attachment_id ? (int) wp_get_post_parent_id( $attachment_id ) : 0; if ( ! $parent && isset( $_REQUEST['post_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $parent = absint( $_REQUEST['post_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } if ( ! $parent || BCAL_PT !== get_post_type( $parent ) ) { return $sizes; } $keep = array( 'thumbnail', 'medium', 'medium_large', 'large' ); return array_intersect_key( $sizes, array_flip( $keep ) ); } add_filter( 'intermediate_image_sizes_advanced', 'bcal_limit_image_sizes', 20, 3 );