├── testfile123 ├── index.php ├── admin ├── index.php ├── class-foyer-admin-slide-format-iframe.php ├── class-foyer-admin-slide-format-production.php ├── class-foyer-admin-slide-background-image.php ├── class-foyer-admin-slide-format-text.php ├── class-foyer-admin-slide-format-upcoming-productions.php ├── class-foyer-admin-slide-format-post.php ├── class-foyer-admin-preview.php ├── class-foyer-admin-slide-format-recent-posts.php ├── class-foyer-admin-slide-background-video.php ├── class-foyer-admin-slide-background-html5-video.php ├── class-foyer-admin.php ├── class-foyer-admin-slide-format-pdf.php ├── class-foyer-admin-slide.php └── class-foyer-admin-display.php ├── public ├── index.php ├── assets │ └── manifest.json ├── templates │ ├── slides │ │ ├── backgrounds │ │ │ ├── default.php │ │ │ ├── default-upcoming-productions.php │ │ │ ├── image.php │ │ │ ├── default-production.php │ │ │ ├── html5-video.php │ │ │ └── video.php │ │ ├── default.php │ │ ├── iframe.php │ │ ├── production.php │ │ ├── pdf.php │ │ ├── text.php │ │ ├── upcoming-productions.php │ │ ├── post.php │ │ └── recent-posts.php │ ├── partials │ │ ├── slide.php │ │ └── channel.php │ ├── single-channel.php │ ├── single-slide.php │ ├── single-display.php │ └── preview.php ├── class-foyer-public.php ├── class-foyer-templates.php ├── js │ └── foyer-public-min.js └── css │ └── foyer-public.css ├── includes ├── index.php ├── class-foyer-addons.php ├── class-foyer-theater.php ├── class-foyer-channels.php ├── class-foyer-deactivator.php ├── class-foyer-activator.php ├── class-foyer-displays.php ├── class-foyer-i18n.php ├── class-foyer-setup.php ├── class-foyer-slide-backgrounds.php ├── class-foyer-image-editor-imagick.php ├── class-foyer-channel.php ├── class-foyer-display.php ├── class-foyer.php ├── class-foyer-updater.php ├── class-foyer-slides.php ├── class-foyer-slide.php └── class-foyer-slide-formats.php ├── .gitattributes ├── uninstall.php └── foyer.php /testfile123: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | default_background( $template_args ); 12 | -------------------------------------------------------------------------------- /public/templates/partials/slide.php: -------------------------------------------------------------------------------- 1 | get_format().'.php'); 12 | -------------------------------------------------------------------------------- /public/templates/single-channel.php: -------------------------------------------------------------------------------- 1 | 9 | 12 | > 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/templates/single-slide.php: -------------------------------------------------------------------------------- 1 | 10 | 13 | > 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /public/templates/slides/default.php: -------------------------------------------------------------------------------- 1 | classes(); ?>data_attr();?>> 12 |
13 |
14 | background(); ?> 15 | -------------------------------------------------------------------------------- /public/templates/slides/iframe.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_iframe_website_url', true ) ); 10 | 11 | ?>classes(); ?>data_attr();?>> 12 |
13 | 14 |
15 | background(); ?> 16 | -------------------------------------------------------------------------------- /includes/class-foyer-addons.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Addons { 13 | 14 | /** 15 | * Triggers the 'foyer_loaded' action so add-ons can initialize. 16 | * 17 | * @since 1.7.2 18 | * 19 | * @return void 20 | */ 21 | static function trigger_foyer_loaded() { 22 | do_action( 'foyer_loaded' ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /public/templates/slides/backgrounds/default-upcoming-productions.php: -------------------------------------------------------------------------------- 1 | thumbnail() ) { 11 | 12 | ?>background_classes(); ?>background_data_attr();?>> 13 |
14 | 15 |
16 | get_active_channel() ); 12 | 13 | ?> 14 | 17 | 18 | >classes(); ?>>ID ); 22 | setup_postdata( $post ); 23 | 24 | Foyer_Templates::get_template('partials/channel.php'); 25 | 26 | wp_reset_postdata(); 27 | ?> 32 | 33 | -------------------------------------------------------------------------------- /public/templates/slides/backgrounds/image.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_bg_image_image', true ); 13 | 14 | if ( ! empty( $attachment_id ) ) { 15 | 16 | ?>background_classes(); ?>background_data_attr();?>> 17 |
18 | 19 |
20 | classes(); ?>> 15 |
get_slides() as $slide ) { 18 | 19 | $post = get_post( $slide->ID ); 20 | setup_postdata( $post ); 21 | 22 | Foyer_Templates::get_template('partials/slide.php'); 23 | 24 | wp_reset_postdata(); 25 | } 26 | 27 | ?>
28 | -------------------------------------------------------------------------------- /includes/class-foyer-theater.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class Foyer_Theater { 15 | 16 | /** 17 | * Checks if the Theater for Wordpress plugin is activated. 18 | * 19 | * @since 1.0.0 20 | * @since 1.1.0 Changed method to static. 21 | * 22 | * @return bool 23 | */ 24 | static function is_theater_activated() { 25 | return class_exists( 'WP_Theatre' ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /includes/class-foyer-channels.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Channels { 13 | 14 | /** 15 | * Gets all channel posts. 16 | * 17 | * @since 1.4.0 18 | * 19 | * @param array $args Additional args for get_posts(). 20 | * @return array of WP_Post The channel posts. 21 | */ 22 | static function get_posts( $args = array() ) { 23 | $defaults = array( 24 | 'post_type' => Foyer_Channel::post_type_name, 25 | 'posts_per_page' => -1, 26 | ); 27 | 28 | $args = wp_parse_args( $args, $defaults ); 29 | 30 | return get_posts( $args ); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/templates/slides/backgrounds/default-production.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_production_production_id', true ); 13 | $production = new WPT_Production( $production_id ); 14 | 15 | if ( ! empty( $production) && $production_attachment_id = $production->thumbnail() ) { 16 | 17 | ?>background_classes(); ?>background_data_attr();?>> 18 |
19 | 20 |
21 | 10 | */ 11 | class Foyer_Deactivator { 12 | 13 | /** 14 | * Does some housekeeping at plugin deactivation. 15 | * 16 | * Fired during plugin deactivation. Though when network activated only for the primary site. 17 | * 18 | * @since 1.0.0 19 | * @since 1.5.3 Flushes the rewrite rules to make sure our rewrite rules are removed. 20 | * 21 | * @return void 22 | */ 23 | public static function deactivate() { 24 | 25 | // Our custom post types are not registered at this point 26 | // Re-building rewrite rules, excluding those for our custom post types 27 | flush_rewrite_rules(); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /includes/class-foyer-activator.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class Foyer_Activator { 12 | 13 | /** 14 | * Does some housekeeping at plugin activation. 15 | * 16 | * Fired during plugin activation. Though when network activated only for the primary site. 17 | * 18 | * @since 1.0.0 19 | * @since 1.5.3 Flushes the rewrite rules to make sure pretty permalinks for our custom post types 20 | * work properly after plugin is activated. Fixes #19 for new installs. 21 | * 22 | * @return void 23 | */ 24 | public static function activate() { 25 | 26 | // Make sure our custom post types are registered 27 | Foyer_Setup::register_post_types(); 28 | 29 | // Re-build rewrite rules, including those for our custom post types 30 | flush_rewrite_rules(); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /public/templates/slides/production.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_production_production_id', true ); 14 | $production = new WPT_Production( $production_id ); 15 | 16 | ?>classes(); ?>data_attr();?>> 17 |
18 | 19 |
20 |
title(); ?>
21 |
dates_html(); ?>
22 |
23 | 24 |
25 | background(); ?> 26 | -------------------------------------------------------------------------------- /public/templates/slides/pdf.php: -------------------------------------------------------------------------------- 1 | classes(); ?>data_attr();?>> 25 |
26 |
31 |
32 | background(); ?> 33 | 11 | */ 12 | class Foyer_Displays { 13 | 14 | /** 15 | * Gets all display posts. 16 | * 17 | * @since 1.4.0 18 | * 19 | * @param array $args Additional args for get_posts(). 20 | * @return array of WP_Post The display posts. 21 | */ 22 | static function get_posts( $args = array() ) { 23 | $defaults = array( 24 | 'post_type' => Foyer_Display::post_type_name, 25 | 'posts_per_page' => -1, 26 | ); 27 | 28 | $args = wp_parse_args( $args, $defaults ); 29 | 30 | return get_posts( $args ); 31 | } 32 | 33 | /** 34 | * Adds a request for each display to be reset. 35 | * 36 | * @return void 37 | */ 38 | static function reset_all_displays() { 39 | $display_posts = self::get_posts(); 40 | 41 | foreach ( $display_posts as $display_post ) { 42 | $display = new Foyer_Display( $display_post ); 43 | $display->add_reset_request(); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /public/templates/preview.php: -------------------------------------------------------------------------------- 1 | 9 | 12 | 13 | > 22 |
$orientation_name ) { 24 | ?>
31 | 32 | -------------------------------------------------------------------------------- /uninstall.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_bg_html5_video_video_url', true ); 11 | $video_start = get_post_meta( $slide->ID, 'slide_bg_html5_video_video_start', true ); 12 | $video_end = get_post_meta( $slide->ID, 'slide_bg_html5_video_video_end', true ); 13 | $hold_slide = get_post_meta( $slide->ID, 'slide_bg_html5_video_hold_slide', true ); 14 | $enable_sound = get_post_meta( $slide->ID, 'slide_bg_html5_video_enable_sound', true ); 15 | 16 | if ( ! empty( $video_url ) ) { 17 | 18 | ?>background_classes(); ?>background_data_attr();?>> 19 |
25 | 28 |
29 | 20 | */ 21 | class Foyer_i18n { 22 | 23 | /** 24 | * Load the plugin text domain for translation. 25 | * 26 | * @since 1.0.0 27 | * @since 1.3.2 Changed method to static. 28 | */ 29 | static function load_plugin_textdomain() { 30 | 31 | load_plugin_textdomain( 32 | 'foyer', 33 | false, 34 | dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' 35 | ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /public/templates/slides/backgrounds/video.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_bg_video_video_url', true ); 13 | $video_start = get_post_meta( $slide->ID, 'slide_bg_video_video_start', true ); 14 | $video_end = get_post_meta( $slide->ID, 'slide_bg_video_video_end', true ); 15 | $hold_slide = get_post_meta( $slide->ID, 'slide_bg_video_hold_slide', true ); 16 | $enable_sound = get_post_meta( $slide->ID, 'slide_bg_video_enable_sound', true ); 17 | 18 | // URL is saved in format https://youtu.be/r9tbusKyvMY 19 | // We need the ID, the last bit 20 | $video_id = substr( $video_url, strrpos( $video_url, '/' ) + 1 ); 21 | 22 | if ( ! empty( $video_id ) ) { 23 | 24 | ?>background_classes(); ?>background_data_attr();?>> 25 |
32 | ID, 'slide_text_pretitle', true ); 11 | $slide_text_title = get_post_meta( $slide->ID, 'slide_text_title', true ); 12 | $slide_text_subtitle = get_post_meta( $slide->ID, 'slide_text_subtitle', true ); 13 | $slide_text_content = get_post_meta( $slide->ID, 'slide_text_content', true ); 14 | 15 | ?>classes(); ?>data_attr(); ?>> 16 |
17 |
18 | 19 |
20 | 21 | 22 |
23 | 24 | 25 |
26 | 27 | 28 |
29 | 30 |
31 |
32 | background(); ?> 33 | -------------------------------------------------------------------------------- /public/templates/slides/upcoming-productions.php: -------------------------------------------------------------------------------- 1 | ID, 'slide_upcoming_productions_limit', true ) ); 14 | $categories = get_post_meta( $slide->ID, 'slide_upcoming_productions_categories', true ); 15 | 16 | // Prepare categories for Theater productions query 17 | if ( empty( $categories ) ) { 18 | $categories = array(); 19 | } 20 | else { 21 | $categories = array_map( 'intval', $categories ); 22 | } 23 | 24 | $production_args = array( 25 | 'end_after' => 'now', 26 | 'cat' => implode( ',', $categories ), 27 | 'limit' => $limit, 28 | 'context' => 'foyer_slide_upcoming_productions', 29 | ); 30 | 31 | foreach ( $wp_theatre->productions->get( $production_args ) as $production ) { 32 | 33 | ?>classes(); ?>data_attr();?>> 34 |
35 |
36 |
title(); ?>
37 |
dates_html(); ?>
38 |
39 |
$production ); 42 | $slide->background( $background_args ); 43 | 44 | ?>ID, 'slide_post_post_id', true ); 12 | $slide_post = get_post( $slide_post_id ); 13 | 14 | $slide_post_display_thumbnail = get_post_meta( $slide->ID, 'slide_post_display_thumbnail', true ); 15 | $slide_post_use_excerpt = get_post_meta( $slide->ID, 'slide_post_use_excerpt', true ); 16 | 17 | if ( ! empty( $slide_post_use_excerpt ) ) { 18 | $content = apply_filters( 'the_content', $slide_post->post_excerpt ); 19 | } 20 | else { 21 | $content = apply_filters( 'the_content', $slide_post->post_content ); 22 | } 23 | 24 | ?>classes(); ?>data_attr(); ?>> 25 |
26 | ID ) ) { ?> 27 | ID ) ) { ?> 28 |
29 | 30 |
31 | 32 |
33 |
ID ); ?>
34 |
ID ); ?>
35 | 36 |
37 | 38 |
39 | 40 |
41 | background(); ?> 42 | -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide-format-iframe.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Admin_Slide_Format_Iframe { 13 | 14 | /** 15 | * Saves additional data for the Iframe slide format. 16 | * 17 | * @since 1.3.0 18 | * 19 | * @param int $post_id The ID of the post being saved. 20 | * @return void 21 | */ 22 | static function save_slide( $post_id ) { 23 | $slide_iframe_website_url = sanitize_text_field( $_POST['slide_iframe_website_url'] ); 24 | update_post_meta( $post_id, 'slide_iframe_website_url', $slide_iframe_website_url ); 25 | } 26 | 27 | /** 28 | * Outputs the meta box for the Iframe slide format. 29 | * 30 | * @since 1.3.0 31 | * 32 | * @param WP_Post $post The post of the current slide. 33 | * @return void 34 | */ 35 | static function slide_meta_box( $post ) { 36 | $slide_iframe_website_url = get_post_meta( $post->ID, 'slide_iframe_website_url', true ); 37 | 38 | $https = ( 0 === stripos( 'https://', get_permalink() ) ); 39 | $placeholder = __( 'https://...', 'foyer' ); 40 | 41 | ?> 42 | 43 | 44 | 47 | 54 | 55 | 56 |
45 | 46 | 48 | 50 | 51 |

52 | 53 |
ID, 'slide_recent_posts_limit', true ) ); 11 | $slide_recent_posts_categories = get_post_meta( $slide->ID, 'slide_recent_posts_categories', true ); 12 | 13 | $slide_recent_posts_display_thumbnail = get_post_meta( $slide->ID, 'slide_recent_posts_display_thumbnail', true ); 14 | $slide_recent_posts_use_excerpt = get_post_meta( $slide->ID, 'slide_recent_posts_use_excerpt', true ); 15 | 16 | // Prepare categories and limit for get_posts() query 17 | $post_args = array(); 18 | 19 | if ( ! empty( $slide_recent_posts_categories ) ) { 20 | $post_args['category__in'] = array_map( 'intval', $slide_recent_posts_categories ); 21 | } 22 | 23 | if ( ! empty( $slide_recent_posts_limit ) ) { 24 | $post_args['posts_per_page'] = $slide_recent_posts_limit; 25 | } 26 | else { 27 | $post_args['nopaging'] = true; 28 | } 29 | 30 | foreach ( get_posts( $post_args ) as $slide_post ) { 31 | 32 | if ( ! empty( $slide_recent_posts_use_excerpt ) ) { 33 | $content = apply_filters( 'the_content', $slide_post->post_excerpt ); 34 | } 35 | else { 36 | $content = apply_filters( 'the_content', $slide_post->post_content ); 37 | } 38 | 39 | ?>classes(); ?>data_attr(); ?>> 40 |
41 | ID ) ) { ?> 42 | ID ) ) { ?> 43 |
44 | 45 |
46 | 47 |
48 |
ID ); ?>
49 |
ID ); ?>
50 | 51 |
52 | 53 |
54 | 55 |
56 | background(); ?> 57 | 11 | */ 12 | class Foyer_Admin_Slide_Format_Production { 13 | 14 | /** 15 | * Saves additional data for the Production slide format. 16 | * 17 | * @since 1.0.0 18 | * @since 1.0.1 Improved validating & sanitizing of the user input. 19 | * @since 1.1.0 Moved here from Foyer_Theater, and changed to static. 20 | * @since 1.4.0 Removed saving of slide_production_image since background images are now handled by slide backgrounds. 21 | * 22 | * @param int $post_id The ID of the post being saved. 23 | * @return void 24 | */ 25 | static function save_slide_production( $post_id ) { 26 | $slide_production_production_id = intval( $_POST['slide_production_production_id'] ); 27 | if ( empty( $slide_production_production_id ) ) { 28 | $slide_production_production_id = ''; 29 | } 30 | 31 | update_post_meta( $post_id, 'slide_production_production_id', $slide_production_production_id ); 32 | } 33 | 34 | /** 35 | * Outputs the meta box for the Production slide format. 36 | * 37 | * @since 1.0.0 38 | * @since 1.0.1 Escaped & sanitized the output. 39 | * @since 1.1.0 Moved here from Foyer_Theater, and changed to static. 40 | * @since 1.2.6 Changed the displayed name from Production to Event, same terminology as in Theater for WordPress. 41 | * @since 1.3.1 Fixed two labels that pointed to a non-existent field slide_default_subtitle, via for. 42 | * @since 1.4.0 Removed the slide_production_image admin field since background images are now handled by slide backgrounds. 43 | * 44 | * @param WP_Post $post The post of the current slide. 45 | * @return void 46 | */ 47 | static function slide_production_meta_box( $post ) { 48 | 49 | global $wp_theatre; 50 | 51 | ?> 52 | 53 | 54 | 57 | 66 | 67 | 68 |
55 | 56 | 58 | 65 |
13 | */ 14 | class Foyer_Admin_Slide_Background_Image { 15 | 16 | /** 17 | * Saves the additional data of the Image slide background. 18 | * 19 | * @since 1.4.0 20 | * 21 | * @param int $post_id The Post ID of the slide being saved. 22 | * @return void 23 | */ 24 | static function save_slide_background( $post_id ) { 25 | $slide_bg_image_image = intval( $_POST['slide_bg_image_image'] ); 26 | if ( empty( $slide_bg_image_image ) ) { 27 | $slide_bg_image_image = ''; 28 | } 29 | 30 | update_post_meta( $post_id, 'slide_bg_image_image', $slide_bg_image_image ); 31 | } 32 | 33 | /** 34 | * Outputs the meta box for the Image slide background. 35 | * 36 | * @since 1.4.0 37 | * @since 1.5.2 Added a hint about minimal image sizes. 38 | * Removed the height attribute of the preview image, sizing is now done with CSS. 39 | * @since 1.6.0 Renamed everything slide_image_* to slide_file_*, and 'Upload image' to 'Select image'. 40 | * 41 | * @param WP_Post $post The post of the slide that is being edited. 42 | * @return void 43 | */ 44 | static function slide_background_meta_box( $post ) { 45 | 46 | wp_enqueue_media(); 47 | 48 | $slide_bg_image_image = get_post_meta( $post->ID, 'slide_bg_image_image', true ); 49 | 50 | ?> 51 | 52 | 53 | 56 | 68 | 69 | 70 |
54 | 55 | 57 |
58 |
59 | 60 |
61 | 62 | 63 | 64 | 65 |

66 |
67 |
12 | */ 13 | class Foyer_Setup { 14 | 15 | /** 16 | * Registers the custom post type for slides and channels. 17 | * 18 | * @since 1.0.0 19 | * @since 1.3.2 Changed method to static. 20 | * 21 | * @return void 22 | */ 23 | static function register_post_types() { 24 | 25 | register_post_type( Foyer_Display::post_type_name, 26 | array( 27 | 'labels' => array( 28 | 'name' => _x( 'Displays', 'display cpt', 'foyer' ), 29 | 'singular_name' => _x( 'Display', 'display cpt', 'foyer'), 30 | 'add_new' => _x( 'Add New', 'display cpt', 'foyer'), 31 | 'new_item' => _x( 'New display', 'display cpt', 'foyer' ), 32 | 'view_item' => _x( 'View display', 'display cpt', 'foyer' ), 33 | 'add_new_item' => _x( 'Add new display', 'display cpt', 'foyer' ), 34 | 'edit_item' => _x( 'Edit display', 'display cpt', 'foyer' ), 35 | ), 36 | 'public' => true, 37 | 'has_archive' => false, 38 | 'show_in_menu' => 'foyer', 39 | 'show_in_admin_bar' => true, 40 | 'supports' => array( 'title' ), 41 | 'taxonomies' => array(), 42 | 'rewrite' => array( 'slug' => 'foyer' ), 43 | ) 44 | ); 45 | 46 | register_post_type( Foyer_Channel::post_type_name, 47 | array( 48 | 'labels' => array( 49 | 'name' => _x( 'Channels', 'channel cpt', 'foyer' ), 50 | 'singular_name' => _x( 'Channel', 'channel cpt', 'foyer'), 51 | 'add_new' => _x( 'Add New', 'channel cpt', 'foyer'), 52 | 'new_item' => _x( 'New channel', 'channel cpt', 'foyer' ), 53 | 'view_item' => _x( 'View channel', 'channel cpt', 'foyer' ), 54 | 'add_new_item' => _x( 'Add new channel', 'channel cpt', 'foyer' ), 55 | 'edit_item' => _x( 'Edit channel', 'channel cpt', 'foyer' ), 56 | ), 57 | 'public' => true, 58 | 'has_archive' => false, 59 | 'show_in_menu' => 'foyer', 60 | 'show_in_admin_bar' => true, 61 | 'supports' => array( 'title' ), 62 | 'taxonomies' => array(), 63 | 'rewrite' => false, 64 | ) 65 | ); 66 | 67 | register_post_type( Foyer_Slide::post_type_name, 68 | array( 69 | 'labels' => array( 70 | 'name' => _x( 'Slides', 'slide cpt', 'foyer' ), 71 | 'singular_name' => _x( 'Slide', 'slide cpt', 'foyer' ), 72 | 'add_new' => _x( 'Add New', 'slide cpt', 'foyer'), 73 | 'new_item' => _x( 'New slide', 'slide cpt', 'foyer' ), 74 | 'view_item' => _x( 'View slide', 'slide cpt', 'foyer' ), 75 | 'add_new_item' => _x( 'Add new slide', 'slide cpt', 'foyer' ), 76 | 'edit_item' => _x( 'Edit slide', 'slide cpt', 'foyer' ), 77 | ), 78 | 'public' => true, 79 | 'has_archive' => false, 80 | 'show_in_menu' => 'foyer', 81 | 'show_in_admin_bar' => true, 82 | 'supports' => array( 'title' ), 83 | 'taxonomies' => array(), 84 | 'rewrite' => false, 85 | ) 86 | ); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /includes/class-foyer-slide-backgrounds.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Slide_Backgrounds { 13 | 14 | /** 15 | * Adds the Default slide background. 16 | * 17 | * @since 1.4.0 18 | * 19 | * @param array $slide_backgrounds The current slide backgrounds. 20 | * @return array The slide backgrounds with the Default slide background added. 21 | */ 22 | static function add_default_slide_background( $slide_backgrounds ) { 23 | 24 | $slide_backgrounds['default'] = array( 25 | 'title' => _x( 'Default / none', 'slide-background', 'foyer' ), 26 | 'description' => __( 'Displays the default background for the chosen slide format, if any, or no background.', 'foyer' ), 27 | ); 28 | return $slide_backgrounds; 29 | } 30 | 31 | /** 32 | * Adds the HTML5 Video slide background. 33 | * 34 | * @since 1.6.0 35 | * 36 | * @param array $slide_backgrounds The current slide backgrounds. 37 | * @return array The slide backgrounds with the HTML5 Video slide background added. 38 | */ 39 | static function add_html5_video_slide_background( $slide_backgrounds ) { 40 | 41 | $slide_backgrounds['html5-video'] = array( 42 | 'title' => _x( 'Video', 'slide-background', 'foyer' ), 43 | 'meta_box' => array( 'Foyer_Admin_Slide_Background_Html5_Video', 'slide_background_meta_box' ), 44 | 'save_post' => array( 'Foyer_Admin_Slide_Background_Html5_Video', 'save_slide_background' ), 45 | ); 46 | return $slide_backgrounds; 47 | } 48 | 49 | /** 50 | * Adds the Image slide background. 51 | * 52 | * @since 1.4.0 53 | * 54 | * @param array $slide_backgrounds The current slide backgrounds. 55 | * @return array The slide backgrounds with the Image slide background added. 56 | */ 57 | static function add_image_slide_background( $slide_backgrounds ) { 58 | 59 | $slide_backgrounds['image'] = array( 60 | 'title' => _x( 'Image', 'slide-background', 'foyer' ), 61 | 'meta_box' => array( 'Foyer_Admin_Slide_Background_Image', 'slide_background_meta_box' ), 62 | 'save_post' => array( 'Foyer_Admin_Slide_Background_Image', 'save_slide_background' ), 63 | ); 64 | return $slide_backgrounds; 65 | } 66 | 67 | /** 68 | * Adds the YouTube Video slide background. 69 | * 70 | * @since 1.4.0 71 | * @since 1.6.0 Renamed the slide background from 'Video' to 'YouTube', without changing internal names. 72 | * 73 | * @param array $slide_backgrounds The current slide backgrounds. 74 | * @return array The slide backgrounds with the YouTube Video slide background added. 75 | */ 76 | static function add_video_slide_background( $slide_backgrounds ) { 77 | 78 | $slide_backgrounds['video'] = array( 79 | 'title' => _x( 'YouTube', 'slide-background', 'foyer' ), 80 | 'meta_box' => array( 'Foyer_Admin_Slide_Background_Video', 'slide_background_meta_box' ), 81 | 'save_post' => array( 'Foyer_Admin_Slide_Background_Video', 'save_slide_background' ), 82 | ); 83 | return $slide_backgrounds; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /includes/class-foyer-image-editor-imagick.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | class Foyer_Image_Editor_Imagick extends WP_Image_Editor_Imagick { 11 | 12 | /** 13 | * Get the number of pages in the pdf file. 14 | * 15 | * @since 1.1.0 16 | * 17 | * @return int|WP_Error Number of pages or WP_Error on failure. 18 | */ 19 | public function pdf_get_number_of_pages() { 20 | 21 | try { 22 | $number_of_pages = $this->image->getNumberImages(); 23 | } 24 | catch ( Exception $e ) { 25 | return new WP_Error( 'invalid_image', __( 'Could not read number of pages in image.' ), $this->file ); 26 | } 27 | 28 | return $number_of_pages; 29 | } 30 | 31 | /** 32 | * Prepares a specific page so it can be loaded. 33 | * 34 | * Stores the page number to be used on load(). 35 | * Ddestroys the previously used Imagick object and resets the file pointer to enable loading of a new page. 36 | * 37 | * @since 1.1.0 38 | * 39 | * @param int $page_number The number of the page to prepare for loading. 40 | * @return void 41 | */ 42 | public function pdf_prepare_page_for_load( $page_number ) { 43 | 44 | // Destroy Imagick object, otherwise load() would not load a new page but just return the existing object. 45 | if ( $this->image instanceof Imagick ) { 46 | $this->image->clear(); 47 | $this->image->destroy(); 48 | $this->image = null; 49 | } 50 | 51 | // Restore to initial clean file path without page specifier, otherwise load() would fail because file not found. 52 | $this->file = $this->pdf_file; 53 | 54 | // Store page number to be used on load(). 55 | $this->pdf_page_number = $page_number; 56 | } 57 | /** 58 | * Sets up Imagick for PDF processing. 59 | * 60 | * Overrides WP_Image_Editor_Imagick default PDF setup, since WP 4.7, to allow for loading of individual pages in PDF files. 61 | * 62 | * @since 1.1.0 63 | * @since 1.3.1 Changed access to public, to allow invoking PDF setup on WP < 4.7. 64 | * 65 | * @return string|WP_Error File to load or WP_Error on failure. 66 | */ 67 | public function pdf_setup() { 68 | 69 | try { 70 | // By default, PDFs are rendered in 72 DPI. 71 | // This will generate an output file that has the same width and height in pixels as the PDF input. 72 | $this->image->setResolution( 72, 72 ); 73 | 74 | // Store the clean file path without page specifier, for later use. 75 | if ( ! isset( $this->pdf_file ) ) { 76 | $this->pdf_file = $this->file; 77 | } 78 | 79 | // If no page number is set, assume the entire PDF should be loaded. 80 | if ( ! isset( $this->pdf_page_number ) ) { 81 | $this->pdf_page_number = 0; 82 | return $this->pdf_file; 83 | } 84 | 85 | // Add page specifier to file path, to load this specific page. 86 | return $this->pdf_file . '[' . $this->pdf_page_number . ']'; 87 | } 88 | catch ( Exception $e ) { 89 | return new WP_Error( 'pdf_setup_failed', $e->getMessage(), $this->file ); 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide-format-text.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Admin_Slide_Format_Text { 13 | 14 | /** 15 | * Saves additional data for the Text slide format. 16 | * 17 | * @since 1.5.0 18 | * 19 | * @param int $post_id The ID of the post being saved. 20 | * @return void 21 | */ 22 | static function save_slide( $post_id ) { 23 | $slide_text_pretitle = sanitize_text_field( $_POST['slide_text_pretitle'] ); 24 | $slide_text_title = sanitize_text_field( $_POST['slide_text_title'] ); 25 | $slide_text_subtitle = sanitize_text_field( $_POST['slide_text_subtitle'] ); 26 | $slide_text_content = wp_kses_post( $_POST['slide_text_content'] ); 27 | 28 | update_post_meta( $post_id, 'slide_text_pretitle', $slide_text_pretitle ); 29 | update_post_meta( $post_id, 'slide_text_title', $slide_text_title ); 30 | update_post_meta( $post_id, 'slide_text_subtitle', $slide_text_subtitle ); 31 | update_post_meta( $post_id, 'slide_text_content', $slide_text_content ); 32 | } 33 | 34 | /** 35 | * Outputs the meta box for the Text slide format. 36 | * 37 | * @since 1.5.0 38 | * 39 | * @param WP_Post $post The post of the current slide. 40 | * @return void 41 | */ 42 | static function slide_meta_box( $post ) { 43 | $slide_text_pretitle = get_post_meta( $post->ID, 'slide_text_pretitle', true ); 44 | $slide_text_title = get_post_meta( $post->ID, 'slide_text_title', true ); 45 | $slide_text_subtitle = get_post_meta( $post->ID, 'slide_text_subtitle', true ); 46 | $slide_text_content = get_post_meta( $post->ID, 'slide_text_content', true ); 47 | 48 | ?> 49 | 50 | 51 | 54 | 57 | 58 | 59 | 62 | 65 | 66 | 67 | 70 | 73 | 74 | 75 | 78 | 81 | 82 | 83 |
52 | 53 | 55 | 56 |
60 | 61 | 63 | 64 |
68 | 69 | 71 | 72 |
76 | 77 | 79 | 80 |
11 | */ 12 | class Foyer_Admin_Slide_Format_Upcoming_Productions { 13 | 14 | /** 15 | * Saves additional data for the Upcoming Productions slide format. 16 | * 17 | * @since 1.7.0 18 | * 19 | * @param int $post_id The ID of the post being saved. 20 | * @return void 21 | */ 22 | static function save_slide( $post_id ) { 23 | $slide_upcoming_productions_limit = intval( $_POST['slide_upcoming_productions_limit'] ); 24 | if ( empty( $slide_upcoming_productions_limit ) ) { 25 | $slide_upcoming_productions_limit = ''; 26 | } 27 | 28 | $slide_upcoming_productions_categories = ''; 29 | if ( 30 | ! empty( $_POST['slide_upcoming_productions_categories'] ) && 31 | ! empty( $_POST['slide_upcoming_productions_categories'][0] ) 32 | ) { 33 | $slide_upcoming_productions_categories = array_map( 'intval', $_POST['slide_upcoming_productions_categories'] ); 34 | } 35 | 36 | update_post_meta( $post_id, 'slide_upcoming_productions_limit', $slide_upcoming_productions_limit ); 37 | update_post_meta( $post_id, 'slide_upcoming_productions_categories', $slide_upcoming_productions_categories ); 38 | } 39 | 40 | /** 41 | * Outputs the meta box for the Upcoming Productions slide format. 42 | * 43 | * @since 1.7.0 44 | * 45 | * @param WP_Post $post The post of the current slide. 46 | * @return void 47 | */ 48 | static function slide_meta_box( $post ) { 49 | 50 | $slide_upcoming_productions_limit = intval( get_post_meta( $post->ID, 'slide_upcoming_productions_limit', true ) ); 51 | 52 | $slide_upcoming_productions_categories = get_post_meta( $post->ID, 'slide_upcoming_productions_categories', true ); 53 | if ( empty( $slide_upcoming_productions_categories ) ) { 54 | $slide_upcoming_productions_categories = array(); 55 | } 56 | 57 | ?> 58 | 59 | 60 | 63 | 66 | 67 | 68 | 71 | 78 | 79 | 80 |
61 | 62 | 64 | 65 |
69 | 70 | 72 | 77 |
11 | */ 12 | class Foyer_Admin_Slide_Format_Post { 13 | 14 | /** 15 | * Saves additional data for the Post slide format. 16 | * 17 | * @since 1.5.0 18 | * 19 | * @param int $post_id The ID of the post being saved. 20 | * @return void 21 | */ 22 | static function save_slide( $post_id ) { 23 | $slide_post_post_id = intval( $_POST['slide_post_post_id'] ); 24 | if ( empty( $slide_post_post_id ) ) { 25 | $slide_post_post_id = ''; 26 | } 27 | 28 | $slide_post_display_thumbnail = ''; 29 | if ( isset( $_POST['slide_post_display_thumbnail'] ) ) { 30 | $slide_post_display_thumbnail = intval( $_POST['slide_post_display_thumbnail'] ); 31 | if ( empty( $slide_post_display_thumbnail ) ) { 32 | $slide_post_display_thumbnail = ''; 33 | } 34 | } 35 | 36 | $slide_post_use_excerpt = ''; 37 | if ( isset( $_POST['slide_post_use_excerpt'] ) ) { 38 | $slide_post_use_excerpt = intval( $_POST['slide_post_use_excerpt'] ); 39 | if ( empty( $slide_post_use_excerpt ) ) { 40 | $slide_post_use_excerpt = ''; 41 | } 42 | } 43 | 44 | update_post_meta( $post_id, 'slide_post_post_id', $slide_post_post_id ); 45 | update_post_meta( $post_id, 'slide_post_display_thumbnail', $slide_post_display_thumbnail ); 46 | update_post_meta( $post_id, 'slide_post_use_excerpt', $slide_post_use_excerpt ); 47 | } 48 | 49 | /** 50 | * Outputs the meta box for the Post slide format. 51 | * 52 | * @since 1.5.0 53 | * 54 | * @param WP_Post $post The post of the current slide. 55 | * @return void 56 | */ 57 | static function slide_meta_box( $post ) { 58 | 59 | $args = array( 60 | 'post_type' => 'post', 61 | 'posts_per_page' => -1, 62 | ); 63 | $posts = get_posts( $args ); 64 | 65 | $slide_post_display_thumbnail = get_post_meta( $post->ID, 'slide_post_display_thumbnail', true ); 66 | $slide_post_use_excerpt = get_post_meta( $post->ID, 'slide_post_use_excerpt', true ); 67 | 68 | ?> 69 | 70 | 71 | 74 | 83 | 84 | 85 | 88 | 93 | 94 | 95 | 98 | 103 | 104 | 105 |
72 | 73 | 75 | 82 |
86 | 87 | 89 | /> 91 | 92 |
96 | 97 | 99 | /> 101 | 102 |
12 | */ 13 | class Foyer_Admin_Preview { 14 | 15 | /** 16 | * Enqueues the admin javascript when previewing a slide. 17 | * 18 | * @since 1.0.0 19 | * @since 1.2.5 Register scripts before they are enqueued. 20 | * Makes it possible to enqueue foyer scripts outside of the foyer plugin. 21 | * @since 1.3.2 Changed method to static. 22 | * 23 | * return void 24 | */ 25 | static function enqueue_scripts() { 26 | 27 | wp_register_script( Foyer::get_plugin_name() . '-admin', plugin_dir_url( __FILE__ ) . 'js/foyer-admin-min.js', array( 'jquery', 'jquery-ui-sortable' ), Foyer::get_version(), false ); 28 | 29 | wp_localize_script( Foyer::get_plugin_name() . '-admin', 'foyer_preview', array( 30 | 'ajax_url' => admin_url( 'admin-ajax.php' ), 31 | 'object_id' => get_the_id(), 32 | 'orientations' => self::get_orientations(), 33 | ) ); 34 | 35 | if ( ! is_user_logged_in() ) { 36 | return; 37 | } 38 | 39 | if ( ! empty( $_GET['foyer-preview'] ) ) { 40 | return; 41 | } 42 | 43 | if ( ! is_singular( array( Foyer_Display::post_type_name, Foyer_Channel::post_type_name, Foyer_Slide::post_type_name) ) ) { 44 | return; 45 | } 46 | 47 | wp_enqueue_script( Foyer::get_plugin_name() . '-admin' ); 48 | } 49 | 50 | /** 51 | * Get the current user's orientation choice for a Display, Channel or Slide. 52 | * 53 | * @since 1.0.0 54 | * @param int $object_id 55 | * @return string 56 | */ 57 | static function get_orientation_choice( $object_id ) { 58 | 59 | $default_orientation_choice = '16-9'; 60 | 61 | if ( !is_user_logged_in( ) ) { 62 | return $default_orientation_choice; 63 | } 64 | 65 | $orientation_choices = get_user_meta( get_current_user_id( ), 'foyer_preview_orientation_choices', true ); 66 | 67 | if ( empty( $orientation_choices[ $object_id ] ) ) { 68 | return $default_orientation_choice; 69 | } 70 | 71 | return $orientation_choices[ $object_id ]; 72 | } 73 | 74 | /** 75 | * Gets all available preview orientations. 76 | * 77 | * @since 1.0.0 78 | * @return array 79 | */ 80 | static function get_orientations() { 81 | 82 | $orientations = array( 83 | '16-9' => __( 'Landscape', 'foyer' ), 84 | '9-16' => __( 'Portrait', 'foyer' ), 85 | ); 86 | 87 | return $orientations; 88 | } 89 | 90 | /** 91 | * Hides the admin bar when a Display, Channel of Slides is shown inside a preview iframe. 92 | * 93 | * @since 1.0.0 94 | * @return bool 95 | */ 96 | static function hide_admin_bar( $show_admin_bar ) { 97 | 98 | // Leave alone if admin bar is already hidden. 99 | if ( !$show_admin_bar ) { 100 | return $show_admin_bar; 101 | } 102 | 103 | // Don't hide if not inside preview iframe. 104 | if ( empty( $_GET['foyer-preview'] ) ) { 105 | return true; 106 | } 107 | 108 | // Don't hide if not viewing a Display, Channel of Slide. 109 | if (!is_singular( array( Foyer_Display::post_type_name, Foyer_Channel::post_type_name, Foyer_Slide::post_type_name) ) ) { 110 | return true; 111 | } 112 | 113 | return false; 114 | } 115 | 116 | /** 117 | * Save a user's orientation choice for a Display, Channel of Slide. 118 | * 119 | * Hooked to orientation button via AJAX. 120 | * 121 | * @since 1.0.0 122 | * @since 1.0.1 Improved validating & sanitizing of the user input. 123 | * @since 1.3.2 Changed method to static. 124 | * 125 | * @return void 126 | */ 127 | static function save_orientation_choice( ) { 128 | 129 | if ( !is_user_logged_in( ) ) { 130 | return; 131 | } 132 | 133 | $orientation = sanitize_title( $_POST[ 'orientation' ] ); 134 | if ( empty( $orientation ) ) { 135 | return; 136 | } 137 | 138 | $object_id = intval( $_POST[ 'object_id' ] ); 139 | if ( empty( $object_id ) ) { 140 | return; 141 | } 142 | 143 | $orientation_choices = get_user_meta( get_current_user_id( ), 'foyer_preview_orientation_choices', true ); 144 | 145 | if (empty( $orientation_choices )) { 146 | $orientation_choices = array(); 147 | } 148 | 149 | $orientation_choices[ $object_id ] = $orientation; 150 | 151 | update_user_meta( get_current_user_id( ), 'foyer_preview_orientation_choices', $orientation_choices ); 152 | 153 | wp_die(); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide-format-recent-posts.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Admin_Slide_Format_Recent_Posts { 13 | 14 | /** 15 | * Saves additional data for the Recent Posts slide format. 16 | * 17 | * @since 1.7.1 18 | * 19 | * @param int $post_id The ID of the post being saved. 20 | * @return void 21 | */ 22 | static function save_slide( $post_id ) { 23 | $slide_recent_posts_limit = intval( $_POST['slide_recent_posts_limit'] ); 24 | if ( empty( $slide_recent_posts_limit ) ) { 25 | $slide_recent_posts_limit = ''; 26 | } 27 | 28 | $slide_recent_posts_categories = ''; 29 | if ( 30 | ! empty( $_POST['slide_recent_posts_categories'] ) && 31 | ! empty( $_POST['slide_recent_posts_categories'][0] ) 32 | ) { 33 | $slide_recent_posts_categories = array_map( 'intval', $_POST['slide_recent_posts_categories'] ); 34 | } 35 | 36 | $slide_recent_posts_display_thumbnail = ''; 37 | if ( isset( $_POST['slide_recent_posts_display_thumbnail'] ) ) { 38 | $slide_recent_posts_display_thumbnail = intval( $_POST['slide_recent_posts_display_thumbnail'] ); 39 | if ( empty( $slide_recent_posts_display_thumbnail ) ) { 40 | $slide_recent_posts_display_thumbnail = ''; 41 | } 42 | } 43 | 44 | $slide_recent_posts_use_excerpt = ''; 45 | if ( isset( $_POST['slide_recent_posts_use_excerpt'] ) ) { 46 | $slide_recent_posts_use_excerpt = intval( $_POST['slide_recent_posts_use_excerpt'] ); 47 | if ( empty( $slide_recent_posts_use_excerpt ) ) { 48 | $slide_recent_posts_use_excerpt = ''; 49 | } 50 | } 51 | 52 | update_post_meta( $post_id, 'slide_recent_posts_limit', $slide_recent_posts_limit ); 53 | update_post_meta( $post_id, 'slide_recent_posts_categories', $slide_recent_posts_categories ); 54 | update_post_meta( $post_id, 'slide_recent_posts_display_thumbnail', $slide_recent_posts_display_thumbnail ); 55 | update_post_meta( $post_id, 'slide_recent_posts_use_excerpt', $slide_recent_posts_use_excerpt ); 56 | } 57 | 58 | /** 59 | * Outputs the meta box for the Recent Posts slide format. 60 | * 61 | * @since 1.7.1 62 | * 63 | * @param WP_Post $post The post of the current slide. 64 | * @return void 65 | */ 66 | static function slide_meta_box( $post ) { 67 | 68 | $slide_recent_posts_limit = intval( get_post_meta( $post->ID, 'slide_recent_posts_limit', true ) ); 69 | 70 | $slide_recent_posts_categories = get_post_meta( $post->ID, 'slide_recent_posts_categories', true ); 71 | if ( empty( $slide_recent_posts_categories ) ) { 72 | $slide_recent_posts_categories = array(); 73 | } 74 | 75 | $slide_recent_posts_display_thumbnail = get_post_meta( $post->ID, 'slide_recent_posts_display_thumbnail', true ); 76 | $slide_recent_posts_use_excerpt = get_post_meta( $post->ID, 'slide_recent_posts_use_excerpt', true ); 77 | 78 | ?> 79 | 80 | 81 | 84 | 87 | 88 | 89 | 92 | 99 | 100 | 101 | 104 | 109 | 110 | 111 | 114 | 119 | 120 | 121 |
82 | 83 | 85 | 86 |
90 | 91 | 93 | 98 |
102 | 103 | 105 | /> 107 | 108 |
112 | 113 | 115 | /> 117 | 118 |
11 | */ 12 | class Foyer_Channel { 13 | 14 | /** 15 | * The Foyer Channel post type name. 16 | * 17 | * @since 1.0.0 18 | * @access private 19 | * @var string $post_type_name The Foyer Channel post type name. 20 | */ 21 | const post_type_name = 'foyer_channel'; 22 | 23 | public $ID; 24 | private $post; 25 | 26 | /** 27 | * The slides of this channel. 28 | * 29 | * @since 1.0.0 30 | * @access private 31 | * @var string $slides The slides of this channel. 32 | */ 33 | private $slides; 34 | 35 | /** 36 | * The slides duration setting of this channel. 37 | * 38 | * @since 1.0.0 39 | * @access private 40 | * @var string $slides The slides duration setting of this channel. 41 | */ 42 | private $slides_duration; 43 | 44 | /** 45 | * The slides transition setting of this channel. 46 | * 47 | * @since 1.0.0 48 | * @access private 49 | * @var string $slides The slides transition setting of this channel. 50 | */ 51 | private $slides_transition; 52 | 53 | /** 54 | * Initialize the class and set its properties. 55 | * 56 | * @since 1.0.0 57 | * @param int or WP_Post $ID The id or the WP_Post object of the channel. 58 | */ 59 | public function __construct( $ID = false ) { 60 | 61 | if ( $ID instanceof WP_Post ) { 62 | // $ID is a WP_Post object 63 | $this->post = $ID; 64 | $ID = $ID->ID; 65 | } 66 | 67 | $this->ID = $ID; 68 | } 69 | 70 | /** 71 | * Outputs the channel classes for use in the template. 72 | * 73 | * The output is escaped, so this method can be used in templates without further escaping. 74 | * 75 | * @since 1.0.1 Escaped the output. 76 | * 77 | * @param array $classes 78 | * @return string 79 | */ 80 | public function classes( $classes = array() ) { 81 | 82 | $classes[] = 'foyer-channel'; 83 | $classes[] = 'foyer-channel-' . intval( $this->ID ); 84 | $classes[] = 'foyer-transition-' . $this->get_slides_transition(); 85 | 86 | if ( empty( $classes ) ) { 87 | return; 88 | } 89 | 90 | ?> class="" slides ) ) { 105 | 106 | $slides = array(); 107 | 108 | $posts = get_post_meta( $this->ID, Foyer_Slide::post_type_name, true ); 109 | 110 | if ( ! empty( $posts ) ) { 111 | foreach ( $posts as $post ) { 112 | 113 | // Only include slides with post status 'publish' 114 | if ( 'publish' != get_post_status( $post ) ) { 115 | continue; 116 | } 117 | 118 | $slide = new Foyer_Slide( $post ); 119 | $slides[] = $slide; 120 | } 121 | } 122 | 123 | $this->slides = $slides; 124 | } 125 | 126 | return $this->slides; 127 | } 128 | 129 | /** 130 | * Get slides duration setting for this channel as saved in the database. 131 | * 132 | * @since 1.0.0 133 | * @access public 134 | * @return string The slides duration setting for this channel as saved in the database. 135 | */ 136 | public function get_saved_slides_duration() { 137 | return get_post_meta( $this->ID, Foyer_Channel::post_type_name . '_slides_duration', true ); 138 | } 139 | 140 | /** 141 | * Get slides transition setting for this channel as saved in the database. 142 | * 143 | * @since 1.0.0 144 | * @access public 145 | * @return string The slides transition setting for this channel as saved in the database. 146 | */ 147 | public function get_saved_slides_transition() { 148 | return get_post_meta( $this->ID, Foyer_Channel::post_type_name . '_slides_transition', true ); 149 | } 150 | 151 | /** 152 | * Get slides duration setting for this channel, or the default slides duration when not set. 153 | * 154 | * @since 1.0.0 155 | * @access public 156 | * @return string The slides duration setting for this channel, or the default slides duration when not set. 157 | */ 158 | public function get_slides_duration() { 159 | 160 | if ( ! isset( $this->slides_duration ) ) { 161 | 162 | $slides_duration = self::get_saved_slides_duration(); 163 | if ( empty( $slides_duration ) ) { 164 | $slides_duration = Foyer_Slides::get_default_slides_duration(); 165 | } 166 | $this->slides_duration = $slides_duration; 167 | } 168 | 169 | return $this->slides_duration; 170 | } 171 | 172 | /** 173 | * Get slides transition setting for this channel, or the default slides transition when not set. 174 | * 175 | * @since 1.0.0 176 | * @access public 177 | * @return string The slides transition setting for this channel, or the default slides transition when not set. 178 | */ 179 | public function get_slides_transition() { 180 | 181 | if ( ! isset( $this->slides_transition ) ) { 182 | 183 | $slides_transition = self::get_saved_slides_transition(); 184 | if ( empty( $slides_transition ) ) { 185 | $slides_transition = Foyer_Slides::get_default_slides_transition(); 186 | } 187 | $this->slides_transition = $slides_transition; 188 | } 189 | 190 | return $this->slides_transition; 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /public/class-foyer-public.php: -------------------------------------------------------------------------------- 1 | 14 | */ 15 | class Foyer_Public { 16 | 17 | /** 18 | * Loads dependencies and registers hooks for the public-facing side of the plugin. 19 | * 20 | * @since 1.3.2 21 | * @since 1.5.4 Added a wp_head action to add the Web App manifest to displays. 22 | */ 23 | static function init() { 24 | self::load_dependencies(); 25 | 26 | /* Foyer_Public */ 27 | add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_styles' ) ); 28 | add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) ); 29 | add_action( 'init', array( __CLASS__, 'add_image_sizes' ) ); 30 | add_action( 'wp_head', array( __CLASS__, 'add_web_app_manifest' ) ); 31 | 32 | /* Foyer_Templates */ 33 | add_action( 'template_include', array( 'Foyer_Templates', 'template_include' ) ); 34 | } 35 | 36 | /** 37 | * Adds image sizes used throughout the front-end of the plugin. 38 | * 39 | * See https://en.wikipedia.org/wiki/Display_resolution for a list of display resolutions and their names. 40 | * 41 | * @since 1.0.0 42 | * @since 1.3.2 Changed method to static. 43 | * @since 1.5.2 Moved away from hard cropped images, instead introduced the soft cropped 'foyer' image size, 44 | * ready for responsive images and higher resolutions. 45 | * 46 | * @return void 47 | */ 48 | static function add_image_sizes() { 49 | 50 | /* 51 | * To be used in templates. 52 | */ 53 | add_image_size( 'foyer', 1920, 1920, false ); // to be set to the same dimensions as the largest internal image size 54 | 55 | /* 56 | * Internal image sizes, to force cropping of different intermediate sizes. 57 | */ 58 | add_image_size( 'foyer_fhd', 1920, 1920, false ); // soft crop: scaled down to fit within 1920x1920 (Full HD) 59 | // add_image_size( 'foyer_4kuhd', 3840, 3840, false ); // soft crop: scaled down to fit within 3840x3840 (4K Ultra HD) 60 | // 4K UHD is disabled for now. 61 | 62 | /* 63 | * @deprecated 1.5.2 64 | * Use 'foyer' instead. 65 | */ 66 | add_image_size( 'foyer_fhd_square', 1920, 1920, true ); // hard cropped to 1920x1920 67 | } 68 | 69 | 70 | /** 71 | * Adds the Web App manifest to the head of Foyer displays. 72 | * 73 | * Only for users that are not logged in. 74 | * 75 | * @since 1.5.4 76 | * 77 | * @return void 78 | */ 79 | static function add_web_app_manifest() { 80 | if ( ! is_singular( Foyer_Display::post_type_name ) ) { 81 | return; 82 | } 83 | 84 | if ( is_user_logged_in() ) { 85 | return; 86 | } 87 | 88 | ?> 11 | */ 12 | class Foyer_Display { 13 | 14 | /** 15 | * The Foyer Display post type name. 16 | * 17 | * @since 1.0.0 18 | * @access private 19 | * @var string $post_type_name The Foyer Display post type name. 20 | */ 21 | const post_type_name = 'foyer_display'; 22 | 23 | public $ID; 24 | private $post; 25 | 26 | /** 27 | * The currently active channel of this display. 28 | * 29 | * @since 1.0.0 30 | * @access private 31 | * @var string $channel The currently active channel of this display. 32 | */ 33 | private $active_channel; 34 | 35 | /** 36 | * The default channel of this display. 37 | * 38 | * @since 1.0.0 39 | * @access private 40 | * @var string $channel The default channel of this display. 41 | */ 42 | private $default_channel; 43 | 44 | /** 45 | * Initialize the class and set its properties. 46 | * 47 | * @since 1.0.0 48 | * @param int or WP_Post $ID The id or the WP_Post object of the display. 49 | */ 50 | public function __construct( $ID = false ) { 51 | 52 | if ( $ID instanceof WP_Post ) { 53 | // $ID is a WP_Post object 54 | $this->post = $ID; 55 | $ID = $ID->ID; 56 | } 57 | 58 | $this->ID = $ID; 59 | } 60 | 61 | /** 62 | * Adds a request for the display to be reset. 63 | * 64 | * @since 1.4.0 65 | * 66 | * @return void 67 | */ 68 | public function add_reset_request() { 69 | update_post_meta( $this->ID, 'foyer_reset_display', 1 ); 70 | } 71 | 72 | /** 73 | * Outputs the display classes for use in the template. 74 | * 75 | * The output is escaped, so this method can be used in templates without further escaping. 76 | * 77 | * @since 1.4.0 78 | * 79 | * @param array $classes 80 | * @return void 81 | */ 82 | public function classes( $classes = array() ) { 83 | 84 | $classes[] = 'foyer-display'; 85 | 86 | if ( $this->is_reset_requested() && empty( $_GET['foyer-preview'] ) ) { 87 | // Reset is requested and we are not previewing, add class to invoke reset 88 | $classes[] = 'foyer-reset-display'; 89 | 90 | // Display will be reset, delete reset request 91 | $this->delete_reset_request(); 92 | } 93 | 94 | if ( empty( $classes ) ) { 95 | return; 96 | } 97 | 98 | ?> class="" ID, 'foyer_reset_display' ); 110 | } 111 | 112 | /** 113 | * Get the currently active channel for this display. 114 | * 115 | * @since 1.0.0 116 | * @since 1.3.2 Only uses a schedule if the schedule's channel is set and published. 117 | * 118 | * @access public 119 | * @return Foyer_Channel The currently active channel for this display. 120 | */ 121 | public function get_active_channel() { 122 | 123 | if ( ! isset( $this->active_channel ) ) { 124 | 125 | $active_channel = $this->get_default_channel(); 126 | 127 | $this->active_channel = $active_channel; 128 | 129 | /** 130 | * Check if a temporary channel is scheduled. 131 | */ 132 | $schedule = $this->get_schedule(); 133 | 134 | // Nothing scheduled at all. Return the default channel. 135 | if ( empty( $schedule ) ) { 136 | return $this->active_channel; 137 | } 138 | 139 | // Return the first scheduled channel that matches the current time, has a channel set, and channel is published. 140 | foreach ( $schedule as $scheduled_channel ) { 141 | 142 | if ( $scheduled_channel['start'] > time() ) { 143 | continue; 144 | } 145 | 146 | if ( $scheduled_channel['end'] < time() ) { 147 | continue; 148 | } 149 | 150 | if ( empty( $scheduled_channel['channel'] ) ) { 151 | continue; 152 | } 153 | 154 | // Only use channel with post status 'publish' 155 | if ( 'publish' != get_post_status( $scheduled_channel['channel'] ) ) { 156 | continue; 157 | } 158 | 159 | $this->active_channel = $scheduled_channel['channel']; 160 | 161 | } 162 | } 163 | 164 | return $this->active_channel; 165 | } 166 | 167 | 168 | /** 169 | * Get the default channel for this display. 170 | * 171 | * @since 1.0.0 172 | * @since 1.3.2 Only returns a channel if it is published. 173 | * 174 | * @access public 175 | * @return Foyer_Channel The default channel for this display. 176 | */ 177 | public function get_default_channel() { 178 | 179 | if ( ! isset( $this->default_channel ) ) { 180 | 181 | $default_channel = get_post_meta( $this->ID, Foyer_Channel::post_type_name, true ); 182 | 183 | // Only use channel with post status 'publish' 184 | if ( 'publish' != get_post_status( $default_channel ) ) { 185 | $this->default_channel = false; 186 | } 187 | else { 188 | $this->default_channel = $default_channel; 189 | } 190 | } 191 | 192 | return $this->default_channel; 193 | } 194 | 195 | /** 196 | * Gets all scheduled channels for this display. 197 | * 198 | * @since 1.0.0 199 | * @return array|string All scheduled channels or an empty string if no channels are scheduled. 200 | */ 201 | public function get_schedule() { 202 | $schedule = array(); 203 | 204 | $schedule = get_post_meta( $this->ID, 'foyer_display_schedule', false ); 205 | 206 | return $schedule; 207 | } 208 | 209 | /** 210 | * Checks if a reset is requested for this display. 211 | * 212 | * @since 1.4.0 213 | * 214 | * @return bool True if reset is requested for this display, false otherwise. 215 | */ 216 | private function is_reset_requested() { 217 | return (bool) get_post_meta( $this->ID, 'foyer_reset_display', true ); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide-background-video.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | class Foyer_Admin_Slide_Background_Video { 15 | 16 | /** 17 | * Saves additional data for the Video slide background. 18 | * 19 | * Functionality was copied from Foyer_Admin_Slide_Format_Video (removed). 20 | * 21 | * @since 1.4.0 22 | * @since 1.5.1 Added saving of the slide_bg_video_enable_sound option. 23 | * 24 | * @param int $post_id The ID of the post being saved. 25 | * @return void 26 | */ 27 | static function save_slide_background( $post_id ) { 28 | $slide_bg_video_video_url = sanitize_text_field( $_POST['slide_bg_video_video_url'] ); 29 | 30 | $slide_bg_video_video_start = intval( $_POST['slide_bg_video_video_start'] ); 31 | if ( empty( $slide_bg_video_video_start ) ) { 32 | $slide_bg_video_video_start = ''; 33 | } 34 | 35 | $slide_bg_video_video_end = intval( $_POST['slide_bg_video_video_end'] ); 36 | if ( empty( $slide_bg_video_video_end ) ) { 37 | $slide_bg_video_video_end = ''; 38 | } 39 | 40 | $slide_bg_video_hold_slide = ''; 41 | if ( isset( $_POST['slide_bg_video_hold_slide'] ) ) { 42 | $slide_bg_video_hold_slide = intval( $_POST['slide_bg_video_hold_slide'] ); 43 | if ( empty( $slide_bg_video_hold_slide ) ) { 44 | $slide_bg_video_hold_slide = ''; 45 | } 46 | } 47 | 48 | $slide_bg_video_enable_sound = ''; 49 | if ( isset( $_POST['slide_bg_video_enable_sound'] ) ) { 50 | $slide_bg_video_enable_sound = intval( $_POST['slide_bg_video_enable_sound'] ); 51 | if ( empty( $slide_bg_video_enable_sound ) ) { 52 | $slide_bg_video_enable_sound = ''; 53 | } 54 | } 55 | 56 | update_post_meta( $post_id, 'slide_bg_video_video_url', $slide_bg_video_video_url ); 57 | update_post_meta( $post_id, 'slide_bg_video_video_start', $slide_bg_video_video_start ); 58 | update_post_meta( $post_id, 'slide_bg_video_video_end', $slide_bg_video_video_end ); 59 | update_post_meta( $post_id, 'slide_bg_video_hold_slide', $slide_bg_video_hold_slide ); 60 | update_post_meta( $post_id, 'slide_bg_video_enable_sound', $slide_bg_video_enable_sound ); 61 | } 62 | 63 | /** 64 | * Outputs the meta box for the Video slide background. 65 | * 66 | * @since 1.4.0 67 | * @since 1.5.1 Added a slide_bg_video_enable_sound option. 68 | * @since 1.6.0 Displayed the YouTube video URL input with class large-text. 69 | * 70 | * @param WP_Post $post The post of the current slide. 71 | * @return void 72 | */ 73 | static function slide_background_meta_box( $post ) { 74 | 75 | $slide_bg_video_video_url = get_post_meta( $post->ID, 'slide_bg_video_video_url', true ); 76 | $slide_bg_video_video_start = get_post_meta( $post->ID, 'slide_bg_video_video_start', true ); 77 | $slide_bg_video_video_end = get_post_meta( $post->ID, 'slide_bg_video_video_end', true ); 78 | $slide_bg_video_hold_slide = get_post_meta( $post->ID, 'slide_bg_video_hold_slide', true ); 79 | $slide_bg_video_enable_sound = get_post_meta( $post->ID, 'slide_bg_video_enable_sound', true ); 80 | 81 | ?> 82 | 83 | 84 | 87 | 95 | 96 | 97 | 100 | 105 | 106 | 107 | 110 | 115 | 116 | 117 | 120 | 125 | 126 | 127 | 130 | 135 | 136 | 137 | 140 | 143 | 144 | 145 |
85 | 86 | 88 | 89 | 91 | 94 |
98 | 99 | 101 | 103 | 104 |
108 | 109 | 111 | 113 | 114 |
118 | 119 | 121 | /> 123 | 124 |
128 | 129 | 131 | /> 133 | 134 |
138 | 139 | 141 |
142 |
11 | */ 12 | class Foyer_Templates { 13 | 14 | /** 15 | * Gets a template. 16 | * 17 | * Search for the template and include the file. 18 | * 19 | * Inspired by https://jeroensormani.com/how-to-add-template-files-in-your-plugin/ 20 | * 21 | * @since 1.0.0 22 | * @since 1.5.7 Renamed the overly generic $args to $template_args so it can be re-used within templates. 23 | * 24 | * @param string $template_name Template to load. 25 | * @param array $template_args Args passed for the template file. 26 | * @param string $string $template_path Path to templates. 27 | * @param string $default_path Default path to template files. 28 | * @return void 29 | */ 30 | static function get_template( $template_name, $template_args = array(), $template_path = '', $default_path = '' ) { 31 | if ( is_array( $template_args ) && isset( $template_args ) ) { 32 | extract( $template_args ); 33 | } 34 | $template_file = self::locate_template( $template_name, $template_path, $default_path ); 35 | if ( ! file_exists( $template_file ) ) { 36 | _doing_it_wrong( __FUNCTION__, sprintf( '%s does not exist.', $template_file ), FOYER_PLUGIN_VERSION ); 37 | return false; 38 | } 39 | include $template_file; 40 | } 41 | 42 | /** 43 | * Gets all template paths registered by plugins. 44 | * 45 | * Add-ons can add their plugin template path using Foyer_Templates::register_plugin_template_path(). 46 | * 47 | * @since 1.7.2 48 | * 49 | * @return array All registered plugin template paths. 50 | */ 51 | static function get_plugin_template_paths() { 52 | 53 | $plugin_template_paths = array(); 54 | 55 | /** 56 | * Filter the plugin template paths. 57 | * 58 | * @since 1.7.2 59 | * @param array $plugin_template_paths The currently registered plugin template paths. 60 | */ 61 | $plugin_template_paths = apply_filters( 'foyer/templates/plugin_template_paths', $plugin_template_paths ); 62 | 63 | return $plugin_template_paths; 64 | } 65 | 66 | /** 67 | * Locates a Foyer template. 68 | * 69 | * Search Order: 70 | * 1. /themes/theme/foyer/$template_name 71 | * 2. /$template_name. 72 | * 3. /plugins/foyer/public/templates/$template_name. 73 | * 74 | * Inspired by https://jeroensormani.com/how-to-add-template-files-in-your-plugin/ 75 | * 76 | * @since 1.0.0 77 | * @since 1.7.2 Removed searching the /themes/theme/$template_name path as this is bound to cause 78 | * conflicts with generic template names. 79 | * @since 1.7.2 Added searching registered plugin template paths. This adds add-on plugin support. 80 | * 81 | * @param string $template_name Template to load. 82 | * @param string $template_path Path to templates. 83 | * @param string $default_path Default path to template files. 84 | * @return string Path to the template file. 85 | */ 86 | static function locate_template( $template_name, $template_path = '', $default_path = '' ) { 87 | 88 | // Set template path to foyer folder of theme / registered plugin. 89 | if ( ! $template_path ) { 90 | $template_path = 'foyer/'; 91 | } 92 | // Set default path to templates folder of Foyer plugin. 93 | if ( ! $default_path ) { 94 | $default_path = plugin_dir_path( __FILE__ ) . 'templates/'; // Path to the template folder 95 | } 96 | 97 | // 1. Search template file in active (child)theme. 98 | $template = locate_template( array( 99 | $template_path . $template_name, 100 | ) ); 101 | 102 | // 2. Search template file in registered plugin template paths (if no template found in previous step). 103 | if ( ! $template && $plugin_paths = self::get_plugin_template_paths() ) { 104 | foreach ( $plugin_paths as $plugin_path ) { 105 | $full_path = trailingslashit( $plugin_path ) . $template_name; 106 | if ( file_exists( $full_path ) ) { 107 | $template = $full_path; 108 | break; 109 | } 110 | } 111 | } 112 | 113 | // 3. Fall back to template file in Foyer plugin (if no template found in previous step). 114 | if ( ! $template ) { 115 | $template = $default_path . $template_name; 116 | } 117 | 118 | return apply_filters( 'foyer/templates/template', $template, $template_name, $template_path, $default_path ); 119 | } 120 | 121 | /** 122 | * Registers the template path for an add-on. 123 | * 124 | * @since 1.7.2 125 | * 126 | * @param string $template_path Path to templates for this plugin. 127 | * @return void 128 | */ 129 | static function register_plugin_template_path( $template_path ) { 130 | add_filter( 131 | 'foyer/templates/plugin_template_paths', 132 | function( $plugin_template_paths ) use ( $template_path ) { 133 | $plugin_template_paths[] = $template_path; 134 | return $plugin_template_paths; 135 | }, 136 | 5 137 | ); 138 | } 139 | 140 | /** 141 | * Template loader. 142 | * 143 | * The template loader will check if WP is loading a template for a Foyer post type 144 | * and will try to load the template from our 'templates' directory. 145 | * 146 | * @since 1.0.0 147 | * 148 | * @param string $template Template file that is being loaded. 149 | * @return string Template file that should be loaded. 150 | */ 151 | static function template_include( $template ) { 152 | 153 | $file = ''; 154 | 155 | if ( 156 | is_singular( array( Foyer_Slide::post_type_name, Foyer_Channel::post_type_name, Foyer_Display::post_type_name ) ) && 157 | is_user_logged_in( ) && 158 | empty( $_GET['foyer-preview'] ) 159 | ) { 160 | // Show inside preview iframe when logged in. 161 | $file = 'preview.php'; 162 | } 163 | else if ( is_singular( Foyer_Slide::post_type_name ) ) { 164 | $file = 'single-slide.php'; 165 | } 166 | else if ( is_singular( Foyer_Channel::post_type_name ) ) { 167 | $file = 'single-channel.php'; 168 | } 169 | else if ( is_singular( Foyer_Display::post_type_name ) ) { 170 | $file = 'single-display.php'; 171 | } 172 | else { 173 | return $template; 174 | } 175 | 176 | if ( file_exists( self::locate_template( $file ) ) ) { 177 | $template = self::locate_template( $file ); 178 | } 179 | 180 | return $template; 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /includes/class-foyer.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class Foyer { 19 | 20 | /** 21 | * Initializes the plugin. 22 | * 23 | * Loads dependencies, defines the locale and registers all of the hooks related to the 24 | * general functionality of the plugin (not public/admin specific). 25 | * 26 | * @since 1.3.2 Changed method to static. 27 | * @since 1.4.0 Registered hooks for slide backgrounds. 28 | * Changed priority of slide format filters to make sure they are triggered before 29 | * filters with default priority. 30 | * @since 1.5.3 Changed priority of Foyer_Setup::register_post_types() on init to 5 to make sure it is 31 | * triggered before filters with default priority, and before the occasional flush_rewrite_rules() 32 | * after updating. 33 | * @since 1.6.0 Registered a hook that adds the HTML5 Video slide background. 34 | * @since 1.7.0 Registered a hook that adds the Upcoming Events slide format. 35 | * @since 1.7.1 Registered a hook that adds the Recent Posts slide format. 36 | * @since 1.7.2 Registered a hook to trigger the 'foyer_loaded' action that can be used by add-ons. 37 | */ 38 | static function init() { 39 | 40 | self::load_dependencies(); 41 | 42 | /* Foyer_Updater */ 43 | add_action( 'plugins_loaded', array( 'Foyer_Updater', 'update' ) ); 44 | 45 | /* Foyer_i18n */ 46 | add_action( 'plugins_loaded', array( 'Foyer_i18n', 'load_plugin_textdomain' ) ); 47 | 48 | /* Foyer_Addons */ 49 | add_action( 'plugins_loaded', array( 'Foyer_Addons', 'trigger_foyer_loaded' ) ); 50 | 51 | /* Foyer_Setup */ 52 | add_action( 'init', array( 'Foyer_Setup', 'register_post_types' ), 5 ); 53 | 54 | /* Foyer_Slide_Backgrounds */ 55 | add_filter( 'foyer/slides/backgrounds', array( 'Foyer_Slide_Backgrounds', 'add_default_slide_background' ), 5 ); 56 | add_filter( 'foyer/slides/backgrounds', array( 'Foyer_Slide_Backgrounds', 'add_image_slide_background' ), 5 ); 57 | add_filter( 'foyer/slides/backgrounds', array( 'Foyer_Slide_Backgrounds', 'add_video_slide_background' ), 5 ); 58 | add_filter( 'foyer/slides/backgrounds', array( 'Foyer_Slide_Backgrounds', 'add_html5_video_slide_background' ), 5 ); 59 | 60 | /* Foyer_Slide_Formats */ 61 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_default_slide_format' ), 5 ); 62 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_text_slide_format' ), 5 ); 63 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_post_slide_format' ), 5 ); 64 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_production_slide_format' ), 5 ); 65 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_iframe_slide_format' ), 5 ); 66 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_recent_posts_slide_format' ), 5 ); 67 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_upcoming_productions_slide_format' ), 5 ); 68 | add_filter( 'foyer/slides/formats', array( 'Foyer_Slide_Formats', 'add_pdf_slide_format' ), 5 ); 69 | } 70 | 71 | /** 72 | * The name of the plugin used to uniquely identify it within the context of 73 | * WordPress and to define internationalization functionality. 74 | * 75 | * @since 1.0.0 76 | * @since 1.3.2 Changed method to static. 77 | * Now uses a named constant. 78 | * 79 | * @return string The name of the plugin. 80 | */ 81 | static function get_plugin_name() { 82 | return FOYER_PLUGIN_NAME; 83 | } 84 | 85 | /** 86 | * Retrieve the version number of the plugin. 87 | * 88 | * @since 1.0.0 89 | * @since 1.3.2 Changed method to static. 90 | * Now uses a named constant. 91 | * 92 | * @return string The version of the plugin. 93 | */ 94 | static function get_version() { 95 | return FOYER_PLUGIN_VERSION; 96 | } 97 | 98 | /** 99 | * Load the required dependencies for this plugin. 100 | * 101 | * Includes the following files that make up the plugin: 102 | * 103 | * - All general (not public/admin) classes. 104 | * - Foyer_Admin: Defines all functionality for the admin area and registers its hooks. 105 | * - Foyer_Public: Defines all functionality for the public side of the site and registers its hooks. 106 | * 107 | * @since 1.0.0 108 | * @since 1.3.2 Changed method to static. 109 | * @since 1.4.0 Included includes/class-foyer-slide-backgrounds.php. 110 | * Included includes/class-foyer-updater.php. 111 | * Included includes/class-foyer-displays.php. 112 | * Included includes/class-foyer-channels.php. 113 | * @since 1.7.2 Included includes/class-foyer-addons.php. 114 | * 115 | * @access private 116 | */ 117 | private static function load_dependencies() { 118 | 119 | /** 120 | * ------ General (not public/admin) ------ 121 | */ 122 | 123 | /* Display, channel and slide models. */ 124 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-display.php'; 125 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-channel.php'; 126 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-slide.php'; 127 | 128 | /* Display, channel and slide helper functions. */ 129 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-displays.php'; 130 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-channels.php'; 131 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-slides.php'; 132 | 133 | /* Database updater. */ 134 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-updater.php'; 135 | 136 | /* Setup of internationalization. */ 137 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-i18n.php'; 138 | 139 | /* Add-ons. */ 140 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-addons.php'; 141 | 142 | /* General (not public/admin) setup actions. */ 143 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-setup.php'; 144 | 145 | /* Slide backgrounds. */ 146 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-slide-backgrounds.php'; 147 | 148 | /* Slide formats. */ 149 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-slide-formats.php'; 150 | 151 | /* Theater for WordPress helper functions. */ 152 | require_once FOYER_PLUGIN_PATH . 'includes/class-foyer-theater.php'; 153 | 154 | 155 | /** 156 | * ------ Admin ------ 157 | */ 158 | 159 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin.php'; 160 | Foyer_Admin::init(); 161 | 162 | /** 163 | * ------ Public ------ 164 | */ 165 | 166 | require_once FOYER_PLUGIN_PATH . 'public/class-foyer-public.php'; 167 | Foyer_Public::init(); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide-background-html5-video.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Admin_Slide_Background_Html5_Video { 13 | 14 | /** 15 | * Saves additional data for the Video slide background. 16 | * 17 | * @since 1.6.0 18 | * 19 | * @param int $post_id The ID of the post being saved. 20 | * @return void 21 | */ 22 | static function save_slide_background( $post_id ) { 23 | $slide_bg_html5_video_video = intval( $_POST['slide_bg_html5_video_video'] ); 24 | if ( empty( $slide_bg_html5_video_video ) ) { 25 | $slide_bg_html5_video_video = ''; 26 | } 27 | 28 | $slide_bg_html5_video_video_url = sanitize_text_field( $_POST['slide_bg_html5_video_video_url'] ); 29 | 30 | $slide_bg_html5_video_video_start = intval( $_POST['slide_bg_html5_video_video_start'] ); 31 | if ( empty( $slide_bg_html5_video_video_start ) ) { 32 | $slide_bg_html5_video_video_start = ''; 33 | } 34 | 35 | $slide_bg_html5_video_video_end = intval( $_POST['slide_bg_html5_video_video_end'] ); 36 | if ( empty( $slide_bg_html5_video_video_end ) ) { 37 | $slide_bg_html5_video_video_end = ''; 38 | } 39 | 40 | $slide_bg_html5_video_hold_slide = ''; 41 | if ( isset( $_POST['slide_bg_html5_video_hold_slide'] ) ) { 42 | $slide_bg_html5_video_hold_slide = intval( $_POST['slide_bg_html5_video_hold_slide'] ); 43 | if ( empty( $slide_bg_html5_video_hold_slide ) ) { 44 | $slide_bg_html5_video_hold_slide = ''; 45 | } 46 | } 47 | 48 | $slide_bg_html5_video_enable_sound = ''; 49 | if ( isset( $_POST['slide_bg_html5_video_enable_sound'] ) ) { 50 | $slide_bg_html5_video_enable_sound = intval( $_POST['slide_bg_html5_video_enable_sound'] ); 51 | if ( empty( $slide_bg_html5_video_enable_sound ) ) { 52 | $slide_bg_html5_video_enable_sound = ''; 53 | } 54 | } 55 | 56 | update_post_meta( $post_id, 'slide_bg_html5_video_video', $slide_bg_html5_video_video ); 57 | update_post_meta( $post_id, 'slide_bg_html5_video_video_url', $slide_bg_html5_video_video_url ); 58 | update_post_meta( $post_id, 'slide_bg_html5_video_video_start', $slide_bg_html5_video_video_start ); 59 | update_post_meta( $post_id, 'slide_bg_html5_video_video_end', $slide_bg_html5_video_video_end ); 60 | update_post_meta( $post_id, 'slide_bg_html5_video_hold_slide', $slide_bg_html5_video_hold_slide ); 61 | update_post_meta( $post_id, 'slide_bg_html5_video_enable_sound', $slide_bg_html5_video_enable_sound ); 62 | } 63 | 64 | /** 65 | * Outputs the meta box for the Video slide background. 66 | * 67 | * @since 1.6.0 68 | * 69 | * @param WP_Post $post The post of the current slide. 70 | * @return void 71 | */ 72 | static function slide_background_meta_box( $post ) { 73 | 74 | wp_enqueue_media(); 75 | 76 | $slide_bg_html5_video_video = get_post_meta( $post->ID, 'slide_bg_html5_video_video', true ); 77 | $slide_bg_html5_video_video_url = get_post_meta( $post->ID, 'slide_bg_html5_video_video_url', true ); 78 | $slide_bg_html5_video_video_start = get_post_meta( $post->ID, 'slide_bg_html5_video_video_start', true ); 79 | $slide_bg_html5_video_video_end = get_post_meta( $post->ID, 'slide_bg_html5_video_video_end', true ); 80 | $slide_bg_html5_video_hold_slide = get_post_meta( $post->ID, 'slide_bg_html5_video_hold_slide', true ); 81 | $slide_bg_html5_video_enable_sound = get_post_meta( $post->ID, 'slide_bg_html5_video_enable_sound', true ); 82 | 83 | ?> 84 | 85 | 86 | 89 | 104 | 105 | 106 | 109 | 114 | 115 | 116 | 119 | 124 | 125 | 126 | 129 | 134 | 135 | 136 | 139 | 144 | 145 | 146 | 149 | 156 | 157 | 158 |
87 | 88 | 90 |
91 | 92 | 93 | 94 | 97 | 98 | 99 | 100 | 101 |

102 |
103 |
107 | 108 | 110 | 112 | 113 |
117 | 118 | 120 | 122 | 123 |
127 | 128 | 130 | /> 132 | 133 |
137 | 138 | 140 | /> 142 | 143 |
147 | 148 | 150 |
151 | 154 |
155 |
14 | */ 15 | class Foyer_Admin { 16 | 17 | /** 18 | * Loads dependencies and registers hooks for the admin-facing side of the plugin. 19 | * 20 | * @since 1.3.2 21 | */ 22 | static function init() { 23 | self::load_dependencies(); 24 | 25 | /* Foyer_Admin */ 26 | add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_styles' ) ); 27 | add_action( 'admin_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) ); 28 | add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ) ); 29 | 30 | /* Foyer_Admin_Display */ 31 | add_action( 'admin_enqueue_scripts', array( 'Foyer_Admin_Display', 'localize_scripts' ) ); 32 | add_action( 'add_meta_boxes', array( 'Foyer_Admin_Display', 'add_channel_editor_meta_box' ) ); 33 | add_action( 'add_meta_boxes', array( 'Foyer_Admin_Display', 'add_channel_scheduler_meta_box' ) ); 34 | add_action( 'save_post', array( 'Foyer_Admin_Display', 'save_display' ) ); 35 | add_filter( 'manage_'.Foyer_Display::post_type_name.'_posts_columns', array( 'Foyer_Admin_Display', 'add_channel_columns' ) ); 36 | add_action( 'manage_'.Foyer_Display::post_type_name.'_posts_custom_column', array( 'Foyer_Admin_Display', 'do_channel_columns' ), 10, 2 ); 37 | /* Foyer_Admin_Channel */ 38 | add_action( 'admin_enqueue_scripts', array( 'Foyer_Admin_Channel', 'localize_scripts' ) ); 39 | add_action( 'add_meta_boxes', array( 'Foyer_Admin_Channel', 'add_slides_editor_meta_box' ), 20 ); 40 | add_action( 'add_meta_boxes', array( 'Foyer_Admin_Channel', 'add_slides_settings_meta_box' ), 40 ); 41 | add_action( 'save_post', array( 'Foyer_Admin_Channel', 'save_channel' ) ); 42 | add_action( 'wp_ajax_foyer_slides_editor_add_slide', array( 'Foyer_Admin_Channel', 'add_slide_over_ajax' ) ); 43 | add_action( 'wp_ajax_foyer_slides_editor_remove_slide', array( 'Foyer_Admin_Channel', 'remove_slide_over_ajax' ) ); 44 | add_action( 'wp_ajax_foyer_slides_editor_reorder_slides', array( 'Foyer_Admin_Channel', 'reorder_slides_over_ajax' ) ); 45 | add_filter( 'get_sample_permalink_html', array( 'Foyer_Admin_Channel', 'remove_sample_permalink' ) ); 46 | add_filter( 'manage_'.Foyer_Channel::post_type_name.'_posts_columns', array( 'Foyer_Admin_Channel', 'add_slides_count_column' ) ); 47 | add_action( 'manage_'.Foyer_Channel::post_type_name.'_posts_custom_column', array( 'Foyer_Admin_Channel', 'do_slides_count_column' ), 10, 2 ); 48 | 49 | /* Foyer_Admin_Slide */ 50 | add_action( 'admin_enqueue_scripts', array( 'Foyer_Admin_Slide', 'localize_scripts' ) ); 51 | add_action( 'add_meta_boxes', array( 'Foyer_Admin_Slide', 'add_slide_editor_meta_boxes' ) ); 52 | add_action( 'save_post', array( 'Foyer_Admin_Slide', 'save_slide' ) ); 53 | add_filter( 'get_sample_permalink_html', array( 'Foyer_Admin_Slide', 'remove_sample_permalink' ) ); 54 | add_filter( 'manage_'.Foyer_Slide::post_type_name.'_posts_columns', array( 'Foyer_Admin_Slide', 'add_slide_format_column' ) ); 55 | add_action( 'manage_'.Foyer_Slide::post_type_name.'_posts_custom_column', array( 'Foyer_Admin_Slide', 'do_slide_format_column' ), 10, 2 ); 56 | 57 | /* Foyer_Admin_Preview */ 58 | add_action( 'wp_enqueue_scripts', array( 'Foyer_Admin_Preview', 'enqueue_scripts' ) ); 59 | add_filter( 'show_admin_bar', array( 'Foyer_Admin_Preview', 'hide_admin_bar' ) ); 60 | add_action( 'wp_ajax_foyer_preview_save_orientation_choice', array( 'Foyer_Admin_Preview', 'save_orientation_choice' ) ); 61 | add_action( 'wp_ajax_nopriv_foyer_preview_save_orientation_choice', array( 'Foyer_Admin_Preview', 'save_orientation_choice' ) ); 62 | 63 | /* Foyer_Admin_Slide_Format_PDF */ 64 | add_filter( 'wp_image_editors', array( 'Foyer_Admin_Slide_Format_PDF', 'add_foyer_imagick_image_editor' ) ); 65 | add_action( 'delete_attachment', array( 'Foyer_Admin_Slide_Format_PDF', 'delete_pdf_images_for_attachment' ) ); 66 | add_action( 'admin_notices', array( 'Foyer_Admin_Slide_Format_PDF', 'display_admin_notice' ) ); 67 | } 68 | 69 | /** 70 | * Adds the top-level Foyer admin menu item. 71 | * 72 | * @since 1.0.0 73 | * @since 1.3.2 Changed method to static. 74 | * Added context for translations. 75 | * @since 1.5.1 Improved the context of the translatable string 'Foyer' to make translation easier. 76 | */ 77 | static function admin_menu() { 78 | add_menu_page( 79 | _x( 'Foyer', 'plugin name in admin menu', 'foyer' ), 80 | _x( 'Foyer', 'plugin name in admin menu', 'foyer' ), 81 | 'edit_posts', 82 | 'foyer', 83 | array(), 84 | 'dashicons-welcome-view-site', 85 | 31 86 | ); 87 | } 88 | 89 | /** 90 | * Enqueues the JavaScript for the admin area. 91 | * 92 | * @since 1.0.0 93 | * @since 1.2.5 Register scripts before they are enqueued. 94 | * Makes it possible to enqueue Foyer scripts outside of the Foyer plugin. 95 | * Changed handle of script to {plugin_name}-admin. 96 | * @since 1.3.2 Changed method to static. 97 | */ 98 | static function enqueue_scripts() { 99 | 100 | wp_register_script( Foyer::get_plugin_name() . '-admin', plugin_dir_url( __FILE__ ) . 'js/foyer-admin-min.js', array( 'jquery', 'jquery-ui-sortable' ), Foyer::get_version(), false ); 101 | wp_enqueue_script( Foyer::get_plugin_name() . '-admin' ); 102 | } 103 | 104 | /** 105 | * Enqueues the stylesheets for the admin area. 106 | * 107 | * @since 1.0.0 108 | * @since 1.3.2 Changed method to static. 109 | */ 110 | static function enqueue_styles() { 111 | 112 | wp_enqueue_style( Foyer::get_plugin_name(), plugin_dir_url( __FILE__ ) . 'css/foyer-admin.css', array(), Foyer::get_version(), 'all' ); 113 | } 114 | 115 | /** 116 | * Loads the required dependencies for the admin-facing side of the plugin. 117 | * 118 | * @since 1.3.2 119 | * @since 1.4.0 Included admin/class-foyer-admin-slide-background-image.php. 120 | * Included admin/class-foyer-admin-slide-background-video.php. 121 | * Removed include admin/class-foyer-admin-slide-format-video.php. 122 | * @since 1.6.0 Included the HTML5 Video slide background admin. 123 | * @since 1.7.0 Included the Upcoming Productions slide background admin. 124 | * 125 | * @access private 126 | */ 127 | private static function load_dependencies() { 128 | 129 | /** 130 | * Admin area functionality for display, channel and slide. 131 | */ 132 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-display.php'; 133 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-channel.php'; 134 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide.php'; 135 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-preview.php'; 136 | 137 | /** 138 | * Admin area functionality for specific slide backgrounds. 139 | */ 140 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-background-image.php'; 141 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-background-video.php'; 142 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-background-html5-video.php'; 143 | 144 | /** 145 | * Admin area functionality for specific slide formats. 146 | */ 147 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-iframe.php'; 148 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-pdf.php'; 149 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-post.php'; 150 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-production.php'; 151 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-recent-posts.php'; 152 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-text.php'; 153 | require_once FOYER_PLUGIN_PATH . 'admin/class-foyer-admin-slide-format-upcoming-productions.php'; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /includes/class-foyer-updater.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class Foyer_Updater { 12 | 13 | /** 14 | * Adds an action on init that flushes the rewrite rules. 15 | * 16 | * @since 1.5.4 17 | * @since 1.5.6 Changed the callback from the non-existing method Foyer_Updater::flush_rewrite_rules() 18 | * to the WordPress core method flush_rewrite_rules(). Fixes #26. 19 | * 20 | * @return void 21 | */ 22 | static function add_flush_rewrite_rules_action() { 23 | 24 | /* 25 | * Flush the rewrite rules on init, right after custom post types are registered. 26 | * 27 | * Fired on the first page load after plugin update. 28 | * When network activated fired for each site. 29 | * When network activated fired when a new site is created on the multisite network. 30 | * 31 | * When network deactivated and later network activated again this is _not_ fired. 32 | * In this situation rewrite rules could go missing for all sites other than the primary site. 33 | */ 34 | add_action( 'init', 'flush_rewrite_rules', 6 ); 35 | } 36 | 37 | /** 38 | * Gets the database version. 39 | * 40 | * @since 1.4.0 41 | * 42 | * @return string The plugin version string stored in the database. 43 | */ 44 | static function get_db_version() { 45 | return get_option( 'foyer_plugin_version' ); 46 | } 47 | 48 | /** 49 | * Renames a meta_key for a post. 50 | * 51 | * @since 1.4.0 52 | * 53 | * @param WP_Post $post The post to rename the meta_key for. 54 | * @param string $old_key The meta_key to rename. 55 | * @param string $new_key The new name for the meta_key. 56 | * @return bool False if meta_key does not exist or value is empty, true otherwise. 57 | */ 58 | static function rename_meta_key_for_post( $post, $old_key, $new_key ) { 59 | 60 | $value = get_post_meta( $post->ID, $old_key, true ); 61 | 62 | if ( empty( $value ) ) { 63 | // Post meta does not exist or contains an empty string, delete just to be sure 64 | delete_post_meta( $post->ID, $old_key, $value ); 65 | return false; 66 | } 67 | 68 | update_post_meta( $post->ID, $new_key, $value ); 69 | delete_post_meta( $post->ID, $old_key, $value ); 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * Resets all displays for certain updates. 76 | * 77 | * @since 1.5.4 78 | * @since 1.5.5 Added 1.5.5 to the list of versions that need displays to reset. 79 | * @since 1.6.0 Added 1.6.0 to the list of versions that need displays to reset. 80 | * @since 1.7.0 Added 1.7.0 to the list of versions that need displays to reset. 81 | * @since 1.7.1 Added 1.7.1 to the list of versions that need displays to reset. 82 | * 83 | * @param string $db_version The current database version. 84 | * @return void 85 | */ 86 | static function reset_displays_for_certain_updates( $db_version ) { 87 | 88 | $reset_displays = false; 89 | 90 | $reset_displays_versions = array( 91 | '1.4.0', 92 | '1.5.0', 93 | '1.5.1', 94 | '1.5.5', 95 | '1.6.0', 96 | '1.7.0', 97 | '1.7.1', 98 | ); 99 | 100 | foreach( $reset_displays_versions as $reset_displays_version ) { 101 | if ( version_compare( $db_version, $reset_displays_version, '<' ) ) { 102 | $reset_displays = true; 103 | } 104 | } 105 | 106 | if ( $reset_displays ) { 107 | // Update contains changes that require CSS/JS to be reloaded, reset displays 108 | Foyer_Displays::reset_all_displays(); 109 | } 110 | } 111 | 112 | /** 113 | * Updates the database to the latest plugin version, if plugin was updated. 114 | * 115 | * Triggered at 'plugins_loaded', before 'init', thus before custom post types are registered. 116 | * 117 | * @since 1.4.0 118 | * @since 1.5.0 Added update code for 1.5.0. 119 | * @since 1.5.1 Added update code for 1.5.1. 120 | * @since 1.5.3 Made sure the rewrite rules are flushed after each update. Fixes #19 for existing installs. 121 | * @since 1.5.4 Made sure no update scripts are run for fresh installs. 122 | * Added a call to a new method that resets displays for certain versions, and removed 123 | * two calls to update methods for versions that only needed to reset displays. 124 | * Moved hooking of flush rewrite rules to its own method. 125 | * 126 | * @return bool True if database was updated, false otherwise. 127 | */ 128 | static function update() { 129 | $db_version = self::get_db_version(); 130 | 131 | if ( $db_version === Foyer::get_version() ) { 132 | // No update needed, bail 133 | return false; 134 | } 135 | 136 | if ( empty( $db_version ) ) { 137 | // Fresh install, make sure all update code is skipped, 138 | // but still continue to flush the rewrite rules and update the db version 139 | $db_version = Foyer::get_version(); 140 | } 141 | 142 | if ( version_compare( $db_version, '1.4.0', '<' ) ) { 143 | // Initial db version is lower than 1.4.0, and this requires some update code 144 | 145 | // Run update to 1.4.0 146 | self::update_to_1_4_0(); 147 | 148 | // Update db version 149 | self::update_db_version( '1.4.0' ); 150 | } 151 | 152 | // Reset displays for certain updates only 153 | self::reset_displays_for_certain_updates( $db_version ); 154 | 155 | // All updates were successful, update db version to current plugin version 156 | self::update_db_version( Foyer::get_version() ); 157 | 158 | // Flush rewrite rules 159 | self::add_flush_rewrite_rules_action(); 160 | 161 | return true; 162 | } 163 | 164 | /** 165 | * Updates the database version. 166 | * 167 | * @since 1.4.0 168 | * 169 | * @param string $version The plugin version string to be stored in the database. 170 | * @return void 171 | */ 172 | static function update_db_version( $version ) { 173 | update_option( 'foyer_plugin_version', $version ); 174 | } 175 | 176 | /** 177 | * Updates the database to version 1.4.0. 178 | * 179 | * All slides in the database are converted to the new slide formats and slide backgrounds introduced in 1.4.0. 180 | * Additionally resets all displays. 181 | * 182 | * @since 1.4.0 183 | * 184 | * @return bool True, update is always successful. 185 | */ 186 | static function update_to_1_4_0() { 187 | 188 | $args = array( 189 | 'post_status' => array( 'any', 'trash' ), 190 | ); 191 | $slides = Foyer_Slides::get_posts( $args ); 192 | 193 | // Loop over all slides and convert them to new slide formats and slide backgrounds 194 | foreach ( $slides as $slide ) { 195 | 196 | $slide_format = get_post_meta( $slide->ID, 'slide_format', true ); 197 | 198 | if ( 'default' == $slide_format ) { 199 | $renamed = self::rename_meta_key_for_post( $slide, 'slide_default_image', 'slide_bg_image_image' ); 200 | 201 | // Always set background to 'image' 202 | update_post_meta( $slide->ID, 'slide_background', 'image' ); 203 | } 204 | elseif ( 'production' == $slide_format ) { 205 | $renamed = self::rename_meta_key_for_post( $slide, 'slide_production_image', 'slide_bg_image_image' ); 206 | if ( $renamed ) { 207 | // Post meta was not empty, set background to 'image' 208 | update_post_meta( $slide->ID, 'slide_background', 'image' ); 209 | } 210 | } 211 | elseif ( 'video' == $slide_format ) { 212 | $renamed = self::rename_meta_key_for_post( $slide, 'slide_video_video_url', 'slide_bg_video_video_url' ); 213 | self::rename_meta_key_for_post( $slide, 'slide_video_video_start', 'slide_bg_video_video_start' ); 214 | self::rename_meta_key_for_post( $slide, 'slide_video_video_end', 'slide_bg_video_video_end' ); 215 | self::rename_meta_key_for_post( $slide, 'slide_video_hold_slide', 'slide_bg_video_hold_slide' ); 216 | 217 | // Always set background to 'video' 218 | update_post_meta( $slide->ID, 'slide_background', 'video' ); 219 | 220 | // Set slide format to 'default' 221 | update_post_meta( $slide->ID, 'slide_format', 'default' ); 222 | } 223 | 224 | $slide_background = get_post_meta( $slide->ID, 'slide_background', true ); 225 | 226 | if ( empty( $slide_background ) ) { 227 | // Slide background is empty, set to 'default' 228 | update_post_meta( $slide->ID, 'slide_background', 'default' ); 229 | } 230 | } 231 | 232 | return true; 233 | } 234 | } 235 | -------------------------------------------------------------------------------- /includes/class-foyer-slides.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Slides { 13 | 14 | /** 15 | * Gets the default slides duration. 16 | * 17 | * @since 1.0.0 18 | * @return int The default slides duration. 19 | */ 20 | static function get_default_slides_duration() { 21 | $default_slides_duration = 8; 22 | 23 | /** 24 | * Filter the default slides duration. 25 | * 26 | * @since 1.0.0 27 | * @param int $default_slides_duration The current default slides duration. 28 | */ 29 | $default_slides_duration = apply_filters( 'foyer/slides/duration/default', $default_slides_duration ); 30 | 31 | return $default_slides_duration; 32 | } 33 | 34 | /** 35 | * Gets the default slides transition. 36 | * 37 | * @since 1.0.0 38 | * @return int The default slides transition. 39 | */ 40 | static function get_default_slides_transition() { 41 | $default_slides_transition = 'fade'; 42 | 43 | /** 44 | * Filter the default slides transition. 45 | * 46 | * @since 1.0.0 47 | * @param int $default_slides_transition The current default slides transition. 48 | */ 49 | $default_slides_transition = apply_filters( 'foyer/slides/transition/default', $default_slides_transition ); 50 | 51 | return $default_slides_transition; 52 | } 53 | 54 | /** 55 | * Gets all slide posts. 56 | * 57 | * @since 1.4.0 58 | * 59 | * @param array $args Additional args for get_posts(). 60 | * @return array of WP_Post The slide posts. 61 | */ 62 | static function get_posts( $args = array() ) { 63 | $defaults = array( 64 | 'post_type' => Foyer_Slide::post_type_name, 65 | 'posts_per_page' => -1, 66 | ); 67 | 68 | $args = wp_parse_args( $args, $defaults ); 69 | 70 | return get_posts( $args ); 71 | } 72 | 73 | /** 74 | * Gets a slide background by its slug. 75 | * 76 | * @since 1.4.0 77 | * @param string $slug The slug of the background to get. 78 | * @return array The slide background properties. 79 | */ 80 | static function get_slide_background_by_slug( $slug ) { 81 | 82 | $slide_backgrounds = self::get_slide_backgrounds(); 83 | 84 | if ( empty( $slide_backgrounds[$slug] ) ) { 85 | return false; 86 | } 87 | 88 | return $slide_backgrounds[$slug]; 89 | } 90 | 91 | /** 92 | * Gets the available slide backgrounds for a slide format, by its slug. 93 | * 94 | * Only returns slide format backgrounds that are registered according to Foyer_Slides::get_slide_backgrounds(). 95 | * 96 | * @since 1.4.0 97 | * @param string $slug The slug of the slide format to get the slide backgrounds for. 98 | * @return array The slide backgrounds with their properties. 99 | */ 100 | static function get_slide_format_backgrounds_by_slug( $slug ) { 101 | 102 | $slide_format = self::get_slide_format_by_slug( $slug ); 103 | 104 | if ( ! empty( $slide_format['slide_backgrounds'] ) ) { 105 | $slide_backgrounds = $slide_format['slide_backgrounds']; 106 | } 107 | else { 108 | // Each slide format should have at least one background, use 'default' 109 | $slide_backgrounds = array( 'default' ); 110 | } 111 | 112 | $slide_format_backgrounds = array(); 113 | 114 | foreach ( $slide_backgrounds as $slide_background_slug ) { 115 | $slide_background_data = self::get_slide_background_by_slug( $slide_background_slug ); 116 | if ( ! empty( $slide_background_data ) ) { 117 | // Only add to backgrounds if this background is registered 118 | $slide_format_backgrounds[$slide_background_slug] = $slide_background_data; 119 | } 120 | } 121 | 122 | return $slide_format_backgrounds; 123 | } 124 | 125 | /** 126 | * Gets a slide background by its slug, for a specific slide format. 127 | * 128 | * Only returns a slide background if it is registered to the slide format. 129 | * 130 | * @since 1.4.0 131 | * @param string $slide_background_slug The slug of the slide background to get. 132 | * @param string $slide_format_slug The slug of the slide format to get the slide background for. 133 | * @return array The slide background properties. 134 | */ 135 | static function get_slide_background_by_slug_for_slide_format( $slide_background_slug, $slide_format_slug ) { 136 | $slide_format_backgrounds = self::get_slide_format_backgrounds_by_slug( $slide_format_slug ); 137 | if ( empty( $slide_format_backgrounds[$slide_background_slug] ) ) { 138 | return false; 139 | } 140 | 141 | return $slide_format_backgrounds[$slide_background_slug]; 142 | } 143 | 144 | /** 145 | * Gets all available slide backgrounds. 146 | * 147 | * Slide backgrounds are added through filters. 148 | * 149 | * @since 1.4.0 150 | * @return array All backgrounds with their properties. 151 | */ 152 | static function get_slide_backgrounds() { 153 | 154 | $slide_backgrounds = array(); 155 | 156 | /** 157 | * Filter available slide backgrounds. 158 | * 159 | * @see Foyer_Slide_Backgrounds::add_image_slide_background() for an example. 160 | * 161 | * @since 1.4.0 162 | * @param array $slide_backgrounds The currently available slide backgrounds. 163 | */ 164 | $slide_backgrounds = apply_filters( 'foyer/slides/backgrounds', $slide_backgrounds ); 165 | 166 | return $slide_backgrounds; 167 | } 168 | 169 | /** 170 | * Gets a slide format by its slug. 171 | * 172 | * @since 1.0.0 173 | * @param string $slug The slug of the format to get. 174 | * @return array The slide format properties. 175 | */ 176 | static function get_slide_format_by_slug( $slug ) { 177 | 178 | foreach( self::get_slide_formats() as $slide_format_key => $slide_format_data ) { 179 | if ( $slug == $slide_format_key ) { 180 | return $slide_format_data; 181 | } 182 | } 183 | 184 | return false; 185 | } 186 | 187 | /** 188 | * Gets all available slide formats. 189 | * 190 | * Slide formats are added through filters. 191 | * 192 | * @since 1.0.0 193 | * @since 1.4.0 Default slide format is now also added through filter, instead of here. 194 | * 195 | * @return array All formats with their properties. 196 | */ 197 | static function get_slide_formats() { 198 | 199 | $slide_formats = array(); 200 | 201 | /** 202 | * Filter available slide formats. 203 | * 204 | * @see Foyer_Slide_Formats::add_production_slide_format() for an example. 205 | * 206 | * @since 1.0.0 207 | * @param array $slide_formats The currently available slide formats. 208 | */ 209 | $slide_formats = apply_filters( 'foyer/slides/formats', $slide_formats ); 210 | 211 | return $slide_formats; 212 | } 213 | 214 | /** 215 | * Gets the available slide backgrounds for each available slide format. 216 | * 217 | * @since 1.4.0 218 | * @return array The slide formats with their backgrounds with their properties. 219 | */ 220 | static function get_slide_formats_backgrounds() { 221 | $slide_formats_backgrounds = array(); 222 | 223 | foreach( self::get_slide_formats() as $slide_format_key => $slide_format_data ) { 224 | $slide_formats_backgrounds[$slide_format_key] = self::get_slide_format_backgrounds_by_slug( $slide_format_key ); 225 | } 226 | 227 | return $slide_formats_backgrounds; 228 | } 229 | 230 | /** 231 | * Checks if the slide format has a default background template. 232 | * 233 | * @since 1.4.0 234 | * 235 | * @param string $slug The slug of the slide format. 236 | * @return bool True if the slide format is known to have a default background template, false otherwise. 237 | */ 238 | static function slide_format_has_default_background_template( $slug ) { 239 | $slide_format_data = self::get_slide_format_by_slug( $slug ); 240 | 241 | if ( empty( $slide_format_data['default_background_template'] ) ) { 242 | return false; 243 | } 244 | return true; 245 | } 246 | 247 | /** 248 | * Checks if the slide format results in a stack of slides. 249 | * 250 | * @since 1.5.0 251 | * 252 | * @param string $slug The slug of the slide format. 253 | * @return bool True if the slide format is known to result in a stack of slides, false otherwise. 254 | */ 255 | static function slide_format_is_stack( $slug ) { 256 | $slide_format_data = self::get_slide_format_by_slug( $slug ); 257 | 258 | if ( empty( $slide_format_data['stack'] ) ) { 259 | return false; 260 | } 261 | return true; 262 | } 263 | } 264 | -------------------------------------------------------------------------------- /includes/class-foyer-slide.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | class Foyer_Slide { 13 | 14 | /** 15 | * The Foyer Slide post type name. 16 | * 17 | * @since 1.0.0 18 | * @access private 19 | * @var string $post_type_name The Foyer Slide post type name. 20 | */ 21 | const post_type_name = 'foyer_slide'; 22 | 23 | public $ID; 24 | private $post; 25 | 26 | /** 27 | * Initialize the class and set its properties. 28 | * 29 | * @since 1.0.0 30 | * @param int or WP_Post $ID The id or the WP_Post object of the slide. 31 | */ 32 | public function __construct( $ID = false ) { 33 | 34 | if ( $ID instanceof WP_Post ) { 35 | // $ID is a WP_Post object 36 | $this->post = $ID; 37 | $ID = $ID->ID; 38 | } 39 | 40 | $this->ID = $ID; 41 | } 42 | 43 | /** 44 | * Outputs the background template HTML for use in the slide format template. 45 | * 46 | * @since 1.4.0 47 | * @since 1.5.7 Added support for template args. 48 | * 49 | * @return string The background template HTML. 50 | */ 51 | public function background( $template_args = false ) { 52 | Foyer_Templates::get_template( 'slides/backgrounds/' . $this->get_background() . '.php', $template_args ); 53 | } 54 | 55 | /** 56 | * Outputs the slide background classes for use in the template. 57 | * 58 | * The output is escaped, so this method can be used in templates without further escaping. 59 | * 60 | * @since 1.4.0 61 | * 62 | * @param array $classes 63 | * @return void 64 | */ 65 | public function background_classes( $classes = array() ) { 66 | 67 | $classes[] = 'foyer-slide-background'; 68 | $classes[] = 'foyer-slide-background-' . $this->get_background(); 69 | 70 | if ( empty( $classes ) ) { 71 | return; 72 | } 73 | 74 | ?> class="" $value ) { 94 | ?> data-=""get_format(); 114 | $classes[] = 'foyer-slide-background-' . $this->get_background(); 115 | 116 | if ( Foyer_Channel::post_type_name == get_post_type( get_queried_object_id() ) ) { 117 | $channel = new Foyer_Channel( get_queried_object_id() ); 118 | } 119 | 120 | if ( Foyer_Display::post_type_name == get_post_type( get_queried_object_id() ) ) { 121 | $display = new Foyer_Display( get_queried_object_id() ); 122 | $channel = new Foyer_Channel( $display->get_active_channel() ); 123 | } 124 | 125 | if ( ! empty ( $channel ) ) { 126 | $slides = $channel->get_slides(); 127 | if ( ! empty( $slides ) && $this->ID == $slides[0]->ID ) { 128 | $classes[] = 'next'; 129 | } 130 | } 131 | 132 | if ( empty( $classes ) ) { 133 | return; 134 | } 135 | 136 | ?> class="" get_format() . '.php', $template_args ); 152 | } 153 | } 154 | 155 | /** 156 | * Outputs the slide data attributes for use in the template. 157 | * 158 | * The output is escaped, so this method can be used in templates without further escaping. 159 | * 160 | * @since 1.0.0 161 | * @since 1.0.1 Escaped the output. 162 | * 163 | * @param array $data 164 | * @return string 165 | */ 166 | public function data_attr( $data = array() ) { 167 | 168 | if ( Foyer_Channel::post_type_name == get_post_type( get_queried_object_id() ) ) { 169 | $channel = new Foyer_Channel( get_queried_object_id() ); 170 | } 171 | 172 | if ( Foyer_Display::post_type_name == get_post_type( get_queried_object_id() ) ) { 173 | $display = new Foyer_Display( get_queried_object_id() ); 174 | $channel = new Foyer_Channel( $display->get_active_channel() ); 175 | } 176 | 177 | if (!empty ($channel) ) { 178 | $data['foyer-slide-duration'] = $channel->get_slides_duration(); 179 | } 180 | 181 | if (empty($data)) { 182 | return; 183 | } 184 | 185 | foreach ( $data as $key=>$value ) { 186 | ?> data-=""ID, 'slide_background', true ); 200 | 201 | $slide_background_keys = array_keys( Foyer_Slides::get_slide_backgrounds() ); 202 | 203 | if ( empty ( $slide_background ) || ! in_array( $slide_background, $slide_background_keys ) ) { 204 | $slide_background = $slide_background_keys[0]; 205 | } 206 | 207 | return $slide_background; 208 | } 209 | 210 | /** 211 | * Gets the format of the slide. 212 | * 213 | * @since 1.0.0 214 | * @since 1.0.1 Renamed from format() to get_format(). 215 | * 216 | * @return string The format key. 217 | */ 218 | public function get_format() { 219 | 220 | $slide_format = get_post_meta( $this->ID, 'slide_format', true ); 221 | 222 | $slide_format_keys = array_keys( Foyer_Slides::get_slide_formats() ); 223 | 224 | if ( empty ( $slide_format ) || ! in_array( $slide_format, $slide_format_keys ) ) { 225 | $slide_format = $slide_format_keys[0]; 226 | } 227 | 228 | return $slide_format; 229 | } 230 | 231 | /** 232 | * Gets the URL of the slide image. 233 | * 234 | * @deprecated 1.4.0 235 | * 236 | * @since 1.0.0 237 | * @since 1.0.1 Renamed from image() to get_image_url(). 238 | * @since 1.3.1 Now returns the image uploaded on the production slide, for production slides. 239 | * @since 1.4.0 Now returns the background image, instead of the default slide or production slide image. 240 | * 241 | * @return string The URL of the slide image. 242 | */ 243 | public function get_image_url() { 244 | _deprecated_function( 'Foyer_Slide::get_image_url()', '1.4.0', '' ); 245 | 246 | $attachment_id = get_post_meta( $this->ID, 'slide_bg_image_image', true ); 247 | $attachment_src = wp_get_attachment_image_src( $attachment_id, 'foyer_fhd_square' ); 248 | 249 | if ( empty ( $attachment_src[0] ) ) { 250 | return false; 251 | } 252 | 253 | return $attachment_src[0]; 254 | } 255 | 256 | /** 257 | * Outputs the URL of the slide image. 258 | * 259 | * The output is escaped, so this method can be used in templates without further escaping. 260 | * 261 | * @deprecated 1.4.0 262 | * 263 | * @since 1.0.1 264 | * @return void 265 | */ 266 | public function image_url() { 267 | _deprecated_function( 'Foyer_Slide::image_url()', '1.4.0', '' ); 268 | echo esc_url( $this->get_image_url() ); 269 | } 270 | 271 | /** 272 | * Checks if the slide results in a stack of slides. 273 | * 274 | * @since 1.5.0 275 | * 276 | * @return bool True if the slide is a stack, false otherwise. 277 | */ 278 | public function is_stack() { 279 | return Foyer_Slides::slide_format_is_stack( self::get_format() ); 280 | } 281 | } 282 | -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide-format-pdf.php: -------------------------------------------------------------------------------- 1 | 10 | */ 11 | class Foyer_Admin_Slide_Format_PDF { 12 | 13 | /** 14 | * Adds our own Foyer_Image_Editor_Imagick image editor to the list of available image editors. 15 | * 16 | * @since 1.1.0 17 | * 18 | * @param array The current list of image editors. 19 | * @return array The list of image editors with our own Foyer_Image_Editor_Imagick added. 20 | */ 21 | static function add_foyer_imagick_image_editor( $editors ) { 22 | 23 | // Image Editor classes are lazy loaded, so we can't just extend them on init 24 | // Include our own image editor now and extend WP_Image_Editor_Imagick 25 | require_once plugin_dir_path( dirname( __FILE__ ) ) . 'includes/class-foyer-image-editor-imagick.php'; 26 | 27 | $editors[] = 'Foyer_Image_Editor_Imagick'; 28 | return $editors; 29 | } 30 | 31 | /** 32 | * Adds PDF images to an attachment, for each page in a PDF. 33 | * 34 | * @since 1.1.0 35 | * 36 | * @param int $attachment_id The ID of the attachment to add PDF images to. 37 | * @return WP_Error|void Returns a WP error if generating of images failed, void otherwise. 38 | */ 39 | static function add_pdf_images_to_attachment( $attachment_id ) { 40 | 41 | $current_pdf_images = get_post_meta( $attachment_id, '_foyer_pdf_images', true ); 42 | 43 | if ( ! empty( $current_pdf_images ) ) { 44 | // Images already added, no need to generate them 45 | return; 46 | } 47 | 48 | $pdf_file_path = get_attached_file( $attachment_id ); 49 | $pdf_images = self::generate_images_for_pdf_pages( $pdf_file_path ); 50 | 51 | if ( is_wp_error( $pdf_images ) ) { 52 | return $pdf_images; 53 | } 54 | 55 | // Convert full paths to paths relative to uploads base, eg. 2017/03/upload_file.pdf 56 | $pdf_images = array_map( 57 | array( __CLASS__, 'get_file_path_relative_to_uploads_base' ), 58 | $pdf_images 59 | ); 60 | 61 | update_post_meta( $attachment_id, '_foyer_pdf_images', $pdf_images ); 62 | } 63 | 64 | /** 65 | * Deletes generated PDF images for an attachment. 66 | * 67 | * @since 1.1.0 68 | * 69 | * @param int $attachment_id The ID of the attachment to delete PDF images for. 70 | * @return void 71 | */ 72 | static function delete_pdf_images_for_attachment( $attachment_id ) { 73 | 74 | $slide_images = get_post_meta( $attachment_id, '_foyer_pdf_images', true ); 75 | 76 | if ( empty( $slide_images ) ) { 77 | // No images were generated, bail 78 | return; 79 | } 80 | 81 | $uploads = wp_upload_dir( null, false ); 82 | 83 | foreach ( $slide_images as $slide_image ) { 84 | 85 | $slide_image_path = trailingslashit( $uploads['basedir'] ) . $slide_image; 86 | wp_delete_file( $slide_image_path ); 87 | } 88 | } 89 | 90 | /** 91 | * Displays an admin notice on the Slide edit screen if something went wrong during saving. 92 | * 93 | * Error is stored in a transient. 94 | * 95 | * @since 1.3.2 96 | * 97 | * @return void 98 | */ 99 | static function display_admin_notice() { 100 | 101 | // Bail if not on Slide edit screen. 102 | $screen = get_current_screen(); 103 | if ( empty( $screen ) || Foyer_Slide::post_type_name != $screen->post_type ) { 104 | return; 105 | } 106 | 107 | if ( $error = get_transient( 'foyer_save_slide_pdf_notice_' . get_the_ID() . '_' . get_current_user_id() ) ) { ?> 108 |
109 |

110 |

111 |
112 | get_error_message(); ?> 113 |

114 |
array( 'pdf_get_number_of_pages', 'pdf_prepare_page_for_load' ) ) ); 149 | if ( is_wp_error( $editor ) ) { 150 | return $editor; 151 | } 152 | 153 | // Check if WordPress install has WP_Image_Editor_Imagick PDF setup support (WP 4.7 and up) 154 | if ( ! method_exists( 'WP_Image_Editor_Imagick', 'pdf_setup' ) ) { 155 | return new WP_Error( 156 | 'wp_image_editor_imagick_pdf_setup', 157 | __( 'Your WordPress version lacks support for PDF processing.', 'foyer' ), 158 | $editor 159 | ); 160 | } 161 | 162 | // Get the number of pages in the PDF 163 | $number_of_pages = $editor->pdf_get_number_of_pages(); 164 | if ( is_wp_error( $number_of_pages ) ) { 165 | return $number_of_pages; 166 | } 167 | 168 | // Loop over all pages 169 | for ( $p = 0; $p < $number_of_pages; $p++ ) { 170 | 171 | $editor->pdf_prepare_page_for_load( $p ); 172 | $loaded = $editor->load(); 173 | 174 | if ( is_wp_error( $loaded ) ) { 175 | return $loaded; 176 | } 177 | 178 | // Created a unique filename that will not overwrite any PNG images that already exist 179 | $dirname = dirname( $pdf_file ) . '/'; 180 | $ext = '.' . pathinfo( $pdf_file, PATHINFO_EXTENSION ); 181 | $png_file = $dirname . wp_unique_filename( $dirname, wp_basename( $pdf_file, $ext ) . '-p' . ( $p + 1 ) . '-pdf.png' ); 182 | 183 | $saved = $editor->save( $png_file, 'image/png' ); 184 | 185 | if ( is_wp_error( $saved ) ) { 186 | return $saved; 187 | } 188 | 189 | // Store file path of the saved PNG image for this page 190 | $png_files[] = $saved['path']; 191 | } 192 | 193 | unset( $editor ); 194 | 195 | return $png_files; 196 | } 197 | 198 | /** 199 | * Gets the file path relative to the uploads base. 200 | * 201 | * Eg. 2017/03/upload_file.pdf 202 | * 203 | * @since 1.1.0 204 | * 205 | * @param string $file_path The full file path to get the relative path for. 206 | * @return string The file path relative to the uploads base. 207 | */ 208 | static function get_file_path_relative_to_uploads_base( $file_path ) { 209 | $uploads = wp_upload_dir( null, false ); 210 | $relative_file_path = str_replace( trailingslashit( $uploads['basedir'] ), '', $file_path ); 211 | 212 | return $relative_file_path; 213 | } 214 | 215 | /** 216 | * Saves additional data for the PDF slide format. 217 | * 218 | * Converts newly selected PDF file to images. 219 | * 220 | * @since 1.1.0 221 | * 222 | * @param int $post_id The ID of the post being saved. 223 | * @return void 224 | */ 225 | static function save_slide_pdf( $post_id ) { 226 | $slide_pdf_file = intval( $_POST['slide_pdf_file'] ); 227 | if ( empty( $slide_pdf_file ) ) { 228 | $slide_pdf_file = ''; 229 | } 230 | 231 | if ( empty( $slide_pdf_file ) ) { 232 | delete_post_meta( $post_id, 'slide_pdf_file' ); 233 | } 234 | else { 235 | 236 | $added = self::add_pdf_images_to_attachment( $slide_pdf_file ); 237 | if ( is_wp_error( $added ) ) { 238 | 239 | // Store our error in a transient so it can be displayed to the user on the Slide edit screen 240 | set_transient( 'foyer_save_slide_pdf_notice_' . $post_id . '_' . get_current_user_id(), $added, 45 ); 241 | 242 | return $added; 243 | } 244 | 245 | update_post_meta( $post_id, 'slide_pdf_file', $slide_pdf_file ); 246 | } 247 | } 248 | 249 | /** 250 | * Outputs the meta box for the Production slide format. 251 | * 252 | * @since 1.0.0 253 | * @since 1.0.1 Escaped & sanitized the output. 254 | * @since 1.1.0 Moved here from Foyer_Theater, and changed to static. 255 | * @since 1.3.1 Added notifications when PDF processing is not supported (no Imagick/Ghostscript installed), 256 | * and when PDF file previews don’t work (PHP < 4.7). 257 | * @since 1.3.2 Removed the notifications added in 1.3.1 as they proved to be unreliable. 258 | * @since 1.6.0 Renamed everything slide_image_* to slide_file_*, and 'Upload PDF' to 'Select PDF'. 259 | * 260 | * @param WP_Post $post The post of the current slide. 261 | * @return void 262 | */ 263 | static function slide_pdf_meta_box( $post ) { 264 | $slide_pdf_file_preview_url = ''; 265 | 266 | $slide_pdf_file = get_post_meta( $post->ID, 'slide_pdf_file', true ); 267 | $slide_pdf_file_src = wp_get_attachment_image_src( $slide_pdf_file, 'full' ); 268 | if ( ! empty( $slide_pdf_file_src ) ) { 269 | $slide_pdf_file_preview_url = $slide_pdf_file_src[0]; 270 | } 271 | 272 | ?> 273 | 274 | 275 | 278 | 289 | 290 | 291 |
276 | 277 | 279 |
280 |
281 | 282 |
283 | 284 | 285 | 286 | 287 |
288 |
11 | */ 12 | class Foyer_Slide_Formats { 13 | 14 | /** 15 | * Adds the Default slide format. 16 | * 17 | * @since 1.4.0 Default slide format is now also added through filter, instead of in Foyer_Slides. 18 | * Added appropriate slide backgrounds to the properties of this slide format. 19 | * @since 1.6.0 Added the HTML5 Video slide background to this slide format's list of available backgrounds. 20 | * 21 | * @param array $slide_formats The current slide formats. 22 | * @return array The slide formats with the Default slide format added. 23 | */ 24 | static function add_default_slide_format( $slide_formats ) { 25 | 26 | $slide_format_backgrounds = array( 'image', 'html5-video', 'video' ); 27 | 28 | /** 29 | * Filter available slide backgrounds for this slide format. 30 | * 31 | * @since 1.4.0 32 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 33 | */ 34 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=default', $slide_format_backgrounds ); 35 | 36 | $slide_formats['default'] = array( 37 | 'title' => _x( 'Default', 'slide-format', 'foyer' ), 38 | 'description' => __( 'Displays a background only.', 'foyer' ), 39 | 'slide_backgrounds' => $slide_format_backgrounds, 40 | ); 41 | return $slide_formats; 42 | } 43 | 44 | /** 45 | * Adds the Iframe slide format. 46 | * 47 | * @since 1.3.0 48 | * @since 1.4.0 Added appropriate slide backgrounds to the properties of this slide format. 49 | * 50 | * @param array $slide_formats The current slide formats. 51 | * @return array The slide formats with the Iframe slide format added. 52 | */ 53 | static function add_iframe_slide_format( $slide_formats ) { 54 | 55 | $slide_format_backgrounds = array( 'default' ); 56 | 57 | /** 58 | * Filter available slide backgrounds for this slide format. 59 | * 60 | * @since 1.4.0 61 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 62 | */ 63 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=iframe', $slide_format_backgrounds ); 64 | 65 | $slide_formats['iframe'] = array( 66 | 'title' => _x( 'External web page', 'slide-format', 'foyer' ), 67 | 'description' => __( 'Displays a web page to your liking.', 'foyer' ), 68 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_Iframe', 'slide_meta_box' ), 69 | 'save_post' => array( 'Foyer_Admin_Slide_Format_Iframe', 'save_slide' ), 70 | 'slide_backgrounds' => $slide_format_backgrounds, 71 | ); 72 | return $slide_formats; 73 | } 74 | 75 | /** 76 | * Adds the PDF slide format. 77 | * 78 | * @since 1.1.0 79 | * @since 1.4.0 Added appropriate slide backgrounds to the properties of this slide format. 80 | * @since 1.5.0 Added the stack property. 81 | * @since 1.6.0 Added the HTML5 Video slide background to this slide format's list of available backgrounds. 82 | * 83 | * @param array $slide_formats The current slide formats. 84 | * @return array The slide formats with the PDF slide format added. 85 | */ 86 | static function add_pdf_slide_format( $slide_formats ) { 87 | 88 | $slide_format_backgrounds = array( 'default', 'image', 'html5-video', 'video' ); 89 | 90 | /** 91 | * Filter available slide backgrounds for this slide format. 92 | * 93 | * @since 1.4.0 94 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 95 | */ 96 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=default', $slide_format_backgrounds ); 97 | 98 | $slide_formats['pdf'] = array( 99 | 'title' => _x( 'PDF', 'slide-format', 'foyer' ), 100 | 'description' => __( 'Displays a slide for each page in the uploaded PDF.', 'foyer' ), 101 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_PDF', 'slide_pdf_meta_box' ), 102 | 'save_post' => array( 'Foyer_Admin_Slide_Format_PDF', 'save_slide_pdf' ), 103 | 'slide_backgrounds' => $slide_format_backgrounds, 104 | 'stack' => true, 105 | ); 106 | return $slide_formats; 107 | } 108 | 109 | /** 110 | * Adds the Post slide format. 111 | * 112 | * @since 1.5.0 113 | * @since 1.6.0 Added the HTML5 Video slide background to this slide format's list of available backgrounds. 114 | * 115 | * @param array $slide_formats The current slide formats. 116 | * @return array The slide formats with the Post slide format added. 117 | */ 118 | static function add_post_slide_format( $slide_formats ) { 119 | 120 | $slide_format_backgrounds = array( 'default', 'image', 'html5-video', 'video' ); 121 | 122 | /** 123 | * Filter available slide backgrounds for this slide format. 124 | * 125 | * @since 1.5.0 126 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 127 | */ 128 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=post', $slide_format_backgrounds ); 129 | 130 | $slide_formats['post'] = array( 131 | 'title' => _x( 'Post', 'slide-format', 'foyer' ), 132 | 'description' => __( 'Displays title, date and content of a post.', 'foyer' ), 133 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_Post', 'slide_meta_box' ), 134 | 'save_post' => array( 'Foyer_Admin_Slide_Format_Post', 'save_slide' ), 135 | 'slide_backgrounds' => $slide_format_backgrounds, 136 | ); 137 | return $slide_formats; 138 | } 139 | 140 | /** 141 | * Adds the Production slide format. 142 | * 143 | * @since 1.0.0 144 | * @since 1.1.0 Moved here from Foyer_Theater, and changed to static. 145 | * @since 1.2.6 Changed the displayed name from Production to Event, same terminology as in Theater for WordPress. 146 | * @since 1.4.0 Added appropriate slide backgrounds to the properties of this slide format. 147 | * @since 1.6.0 Added the HTML5 Video slide background to this slide format's list of available backgrounds. 148 | * 149 | * @param array $slide_formats The current slide formats. 150 | * @return array The slide formats with the Production slide format added. 151 | */ 152 | static function add_production_slide_format( $slide_formats ) { 153 | 154 | if ( ! Foyer_Theater::is_theater_activated() ) { 155 | return $slide_formats; 156 | } 157 | 158 | $slide_format_backgrounds = array( 'default', 'image', 'html5-video', 'video' ); 159 | 160 | /** 161 | * Filter available slide backgrounds for this slide format. 162 | * 163 | * @since 1.4.0 164 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 165 | */ 166 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=production', $slide_format_backgrounds ); 167 | 168 | $slide_formats['production'] = array( 169 | 'title' => _x( 'Event', 'slide-format', 'foyer' ), 170 | 'description' => __( 'Displays title and details of an event, with its image as default background.', 'foyer' ), 171 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_Production', 'slide_production_meta_box' ), 172 | 'save_post' => array( 'Foyer_Admin_Slide_Format_Production', 'save_slide_production' ), 173 | 'slide_backgrounds' => $slide_format_backgrounds, 174 | 'default_background_template' => true, 175 | ); 176 | 177 | return $slide_formats; 178 | } 179 | 180 | /** 181 | * Adds the Recent Posts slide format. 182 | * 183 | * @since 1.7.1 184 | * 185 | * @param array $slide_formats The current slide formats. 186 | * @return array The slide formats with the Recent Posts slide format added. 187 | */ 188 | static function add_recent_posts_slide_format( $slide_formats ) { 189 | 190 | $slide_format_backgrounds = array( 'default', 'image' ); 191 | 192 | /** 193 | * Filter available slide backgrounds for this slide format. 194 | * 195 | * @since 1.7.0 196 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 197 | */ 198 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=recent-posts', $slide_format_backgrounds ); 199 | 200 | $slide_formats['recent-posts'] = array( 201 | 'title' => 'Recent posts', 202 | 'description' => 'Displays a slide for each recent post.', 203 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_Recent_Posts', 'slide_meta_box'), 204 | 'save_post' => array( 'Foyer_Admin_Slide_Format_Recent_Posts', 'save_slide'), 205 | 'slide_backgrounds' => $slide_format_backgrounds, 206 | 'stack' => true, 207 | ); 208 | 209 | return $slide_formats; 210 | } 211 | 212 | /** 213 | * Adds the Text slide format. 214 | * 215 | * @since 1.5.0 216 | * @since 1.5.1 Renamed the slide format from 'Manual text' to 'Text'. 217 | * @since 1.6.0 Added the HTML5 Video slide background to this slide format's list of available backgrounds. 218 | * 219 | * @param array $slide_formats The current slide formats. 220 | * @return array The slide formats with the Text slide format added. 221 | */ 222 | static function add_text_slide_format( $slide_formats ) { 223 | 224 | $slide_format_backgrounds = array( 'default', 'image', 'html5-video', 'video' ); 225 | 226 | /** 227 | * Filter available slide backgrounds for this slide format. 228 | * 229 | * @since 1.5.0 230 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 231 | */ 232 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=text', $slide_format_backgrounds ); 233 | 234 | $slide_formats['text'] = array( 235 | 'title' => _x( 'Text', 'slide-format', 'foyer' ), 236 | 'description' => __( 'Displays some text.', 'foyer' ), 237 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_Text', 'slide_meta_box' ), 238 | 'save_post' => array( 'Foyer_Admin_Slide_Format_Text', 'save_slide' ), 239 | 'slide_backgrounds' => $slide_format_backgrounds, 240 | ); 241 | return $slide_formats; 242 | } 243 | 244 | /** 245 | * Adds the Upcoming Productions slide format. 246 | * 247 | * @since 1.7.0 248 | * 249 | * @param array $slide_formats The current slide formats. 250 | * @return array The slide formats with the Upcoming Productions slide format added. 251 | */ 252 | static function add_upcoming_productions_slide_format( $slide_formats ) { 253 | 254 | if ( ! Foyer_Theater::is_theater_activated() ) { 255 | return $slide_formats; 256 | } 257 | 258 | $slide_format_backgrounds = array( 'default' ); 259 | 260 | /** 261 | * Filter available slide backgrounds for this slide format. 262 | * 263 | * @since 1.7.0 264 | * @param array $slide_format_backgrounds The currently available slide backgrounds for this slide format. 265 | */ 266 | $slide_format_backgrounds = apply_filters( 'foyer/slides/backgrounds/format=upcoming-productions', $slide_format_backgrounds ); 267 | 268 | $slide_formats['upcoming-productions'] = array( 269 | 'title' => 'Upcoming events', 270 | 'description' => 'Displays a slide for each upcoming event.', 271 | 'meta_box' => array( 'Foyer_Admin_Slide_Format_Upcoming_Productions', 'slide_meta_box'), 272 | 'save_post' => array( 'Foyer_Admin_Slide_Format_Upcoming_Productions', 'save_slide'), 273 | 'slide_backgrounds' => $slide_format_backgrounds, 274 | 'default_background_template' => true, 275 | 'stack' => true, 276 | ); 277 | 278 | return $slide_formats; 279 | } 280 | } 281 | -------------------------------------------------------------------------------- /public/js/foyer-public-min.js: -------------------------------------------------------------------------------- 1 | function foyer_display_setup_slide_group_classes(){jQuery(foyer_slides_selector).children().addClass("foyer-slide-group-1")}function foyer_display_setup(){jQuery(this).css("cursor","none"),major_refresh_timeout=setTimeout(foyer_display_reload_window,288e5),foyer_loader_intervalObject=window.setInterval(foyer_display_load_data,3e5)}function foyer_display_load_data(){var e,o;jQuery(".foyer-slide-group-1").length?jQuery(".foyer-slide-group-2").length||(o="foyer-slide-group-2",e="foyer-slide-group-1"):(o="foyer-slide-group-1",e="foyer-slide-group-2"),o&&jQuery.get(window.location,function(t){if($new_html=jQuery(jQuery.parseHTML(jQuery.trim(t))),$new_html.filter(foyer_display_selector).hasClass("foyer-reset-display"))foyer_ticker_shutdown(foyer_display_reload_window);else if($new_html.find(foyer_channel_selector).attr("class")!==jQuery(foyer_channel_selector).attr("class"))foyer_ticker_shutdown(foyer_display_replace_channel,$new_html.find(foyer_channel_selector));else{var i=$new_html.find(foyer_slides_selector).children().addClass(o);1===jQuery(foyer_slides_selector).children().length&&1===$new_html.find(foyer_slides_selector).children().length?(jQuery(foyer_slides_selector).trigger("slides:removing-old-slide-group",e).html(i).trigger("slides:loaded-new-slide-group",o).trigger("slides:removed-old-slide-group"),foyer_ticker_set_slide_active_next_classes()):(jQuery(foyer_slides_selector).children().last().after(i),jQuery(foyer_slides_selector).trigger("slides:loaded-new-slide-group",o),jQuery("body").one("slide:left-active","."+o,function(o){return jQuery(foyer_slides_selector).trigger("slides:removing-old-slide-group",e),jQuery(foyer_slides_selector).find("."+e).remove(),jQuery(foyer_slides_selector).trigger("slides:removed-old-slide-group"),!0}))}})}function foyer_display_replace_channel(e){jQuery(foyer_channel_selector).replaceWith(e),jQuery(foyer_channel_selector).trigger("channel:replaced-channel"),foyer_display_setup_slide_group_classes(),setTimeout(foyer_ticker_init,100)}function foyer_display_reload_window(){window.location.reload()}function foyer_slide_bg_video_bind_display_loading_events(){jQuery("body").on("channel:replaced-channel",foyer_channel_selector,function(e){foyer_yt_api_ready?(foyer_slide_bg_video_init_video_placeholders(),foyer_slide_bg_video_cleanup_youtube_players()):foyer_slide_bg_video_load_youtube_api()}),jQuery("body").on("slides:loaded-new-slide-group",foyer_slides_selector,function(e){foyer_yt_api_ready?foyer_slide_bg_video_init_video_placeholders():foyer_slide_bg_video_load_youtube_api()}),jQuery("body").on("slides:removed-old-slide-group",foyer_slides_selector,function(e){foyer_slide_bg_video_cleanup_youtube_players()})}function foyer_slide_bg_video_bind_ticker_events(){jQuery("body").on("slides:before-binding-events",foyer_slides_selector,function(e){jQuery("body").on("slides:next-slide",foyer_slides_selector,function(e){var o=jQuery(foyer_slide_bg_video_selector).filter(".active").find(".youtube-video-container"),t=window.foyer_yt_players[o.attr("id")];if(1==o.data("foyer-hold-slide")&&t&&"function"==typeof t.playVideo){var i=o.data("foyer-video-end"),r=t.getDuration(),s=t.getCurrentTime();(r=i-foyer_ticker_css_transition_duration||(e.stopImmediatePropagation(),setTimeout(function(){jQuery(foyer_slides_selector).trigger("slides:next-slide")},500))}})}),jQuery("body").on("slide:became-active",foyer_slide_bg_video_selector,function(e){var o=jQuery(this).find(".youtube-video-container"),t=window.foyer_yt_players[o.attr("id")];t&&"function"==typeof t.playVideo&&t.playVideo()}),jQuery("body").on("slide:left-active",foyer_slide_bg_video_selector,function(e){var o=jQuery(this).find(".youtube-video-container"),t=window.foyer_yt_players[o.attr("id")];t&&"function"==typeof t.playVideo&&setTimeout(function(){t.seekTo(o.data("foyer-video-start")),t.pauseVideo()},1e3*foyer_ticker_css_transition_duration)})}function foyer_slide_bg_video_cleanup_youtube_players(){for(var e in window.foyer_yt_players)jQuery("#"+e).length||(delete window.foyer_yt_players[e],jQuery(window).off("resize",function(){foyer_slide_bg_video_resize_youtube_to_cover(e)}))}function foyer_slide_bg_video_init_video_placeholders(){jQuery("div.youtube-video-container").each(function(){var e=jQuery(this);e.attr("id","player-"+Math.random().toString(36).substr(2,16));var o=e.attr("id"),t=e.data("foyer-video-id");o&&t&&(window.foyer_yt_players[o]=new YT.Player(o,{width:"1920",height:"1080",videoId:t,playerVars:{controls:0,modestbranding:1,rel:0,showinfo:0,playsinline:1},events:{onReady:foyer_slide_bg_video_prepare_player_for_playback(o)}}))})}function foyer_slide_bg_video_load_youtube_api(){var e=document.createElement("script");e.src="https://www.youtube.com/iframe_api";var o=document.getElementsByTagName("script")[0];o.parentNode.insertBefore(e,o)}function foyer_slide_bg_video_prepare_player_for_playback(e){return function(o){var t=jQuery("#"+e),i=window.foyer_yt_players[e];foyer_slide_bg_video_resize_youtube_to_cover(e),jQuery(window).on("resize",function(){foyer_slide_bg_video_resize_youtube_to_cover(e)}),window.self!=window.top&&-1!=top.location.href.search("/post.php?")||(t.data("foyer-output-sound")||i.mute(),i.seekTo(t.data("foyer-video-start")),jQuery(foyer_slides_selector).length&&!jQuery("#"+e).parents(foyer_slide_bg_video_selector).hasClass("active")&&i.pauseVideo())}}function foyer_slide_bg_video_resize_youtube_to_cover(e){var o=jQuery("#"+e),t=window.foyer_yt_players[e],i=jQuery(window).width()+0,r=jQuery(window).height()+0;if(i/r>16/9){var s=i/16*9;t.setSize(i,s),o.css({left:"0px"})}else{var _=r/9*16;t.setSize(_,r),o.css({left:-(_-i)/2})}}function onYouTubeIframeAPIReady(){foyer_yt_api_ready=!0,foyer_slide_bg_video_init_video_placeholders()}function foyer_slide_bg_html5_video_bind_ticker_events(){jQuery("body").on("slides:before-binding-events",foyer_slides_selector,function(e){jQuery("body").on("slides:next-slide",foyer_slides_selector,function(e){var o=jQuery(foyer_slide_bg_html5_video_selector).filter(".active").find(".html5-video-container"),t=o.find("video").get(0);t&&1==o.data("foyer-hold-slide")&&t.currentTime>0&&!t.paused&&!t.ended&&t.readyState>2&&(foyer_slide_bg_html5_video_is_almost_ended(o,t)||(e.stopImmediatePropagation(),setTimeout(function(){jQuery(foyer_slides_selector).trigger("slides:next-slide")},500)))})}),jQuery("body").on("slide:became-active",foyer_slide_bg_html5_video_selector,function(e){objectFitPolyfill();var o=jQuery(this).find(".html5-video-container"),t=o.find("video").get(0);t&&(o.data("foyer-output-sound")?t.muted=!1:t.muted=!0,t.addEventListener("playing",function e(){this.removeEventListener("playing",e,!1),this.currentTime=o.data("foyer-video-start")},!1),t.play())}),jQuery("body").on("slide:left-active",foyer_slide_bg_html5_video_selector,function(e){var o=jQuery(this).find(".html5-video-container"),t=o.find("video").get(0);t&&setTimeout(function(){t.pause()},1e3*foyer_ticker_css_transition_duration)})}function foyer_slide_bg_html5_video_is_almost_ended(e,o){if(o){var t=e.data("foyer-video-end"),i=o.duration,r=o.currentTime;if((i=t-foyer_ticker_css_transition_duration)return!0}return!1}function foyer_ticker_bind_events(){jQuery(foyer_slides_selector).trigger("slides:before-binding-events"),jQuery("body").on("slides:next-slide",foyer_slides_selector,function(e){var o=jQuery(foyer_slide_selector+".active");o.trigger("slide:leaving-active");var t=o.next();t.length||(t=jQuery(foyer_slide_selector).first());var i=t.next();i.length||(i=jQuery(foyer_slide_selector).first()),foyer_ticker_shutdown_status?(foyer_ticker_shutdown_status=!1,setTimeout(function(){foyer_ticker_shutdown_callback(foyer_ticker_shutdown_callback_options)},1e3*foyer_ticker_css_transition_duration_safe)):(t.trigger("slide:becoming-active"),i.trigger("slide:becoming-next"),foyer_ticker_set_active_slide_timeout())}),jQuery("body").on("slide:becoming-next",foyer_slide_selector,function(e){jQuery(this).addClass("next").trigger("slide:became-next")}),jQuery("body").on("slide:becoming-active",foyer_slide_selector,function(e){jQuery(this).removeClass("next").addClass("active").trigger("slide:became-active")}),jQuery("body").on("slide:leaving-active",foyer_slide_selector,function(e){jQuery(this).removeClass("active").trigger("slide:left-active")}),jQuery(foyer_slides_selector).trigger("slides:after-binding-events")}function foyer_ticker_init(){foyer_ticker_set_slide_active_next_classes(),foyer_ticker_set_active_slide_timeout()}function foyer_ticker_set_slide_active_next_classes(){jQuery(foyer_slide_selector).first().trigger("slide:becoming-active"),jQuery(foyer_slide_selector).first().next().trigger("slide:becoming-next")}function foyer_ticker_set_active_slide_timeout(){var e=parseFloat(jQuery(foyer_slide_selector+".active").data("foyer-slide-duration"));!e>0&&(e=5),setTimeout(foyer_ticker_next_slide,1e3*e)}function foyer_ticker_next_slide(){jQuery(foyer_slides_selector).trigger("slides:next-slide")}function foyer_ticker_shutdown(e,o){foyer_ticker_shutdown_status=!0,foyer_ticker_shutdown_callback=e,foyer_ticker_shutdown_callback_options=o}var foyer_display_selector=".foyer-display",foyer_channel_selector=".foyer-channel",foyer_slides_selector=".foyer-slides",foyer_slide_selector=".foyer-slide";jQuery(document).ready(function(){jQuery(foyer_display_selector).length&&(foyer_display_setup(),foyer_display_setup_slide_group_classes())}),function(){"use strict";if("undefined"!=typeof window){var e=window.navigator.userAgent.match(/Edge\/(\d{2})\./),o=!!e&&parseInt(e[1],10)>=16;if("objectFit"in document.documentElement.style!=0&&!o)return void(window.objectFitPolyfill=function(){return!1});var t=function(e){var o=window.getComputedStyle(e,null),t=o.getPropertyValue("position"),i=o.getPropertyValue("overflow"),r=o.getPropertyValue("display");t&&"static"!==t||(e.style.position="relative"),"hidden"!==i&&(e.style.overflow="hidden"),r&&"inline"!==r||(e.style.display="block"),0===e.clientHeight&&(e.style.height="100%"),-1===e.className.indexOf("object-fit-polyfill")&&(e.className=e.className+" object-fit-polyfill")},i=function(e){var o=window.getComputedStyle(e,null),t={"max-width":"none","max-height":"none","min-width":"0px","min-height":"0px",top:"auto",right:"auto",bottom:"auto",left:"auto","margin-top":"0px","margin-right":"0px","margin-bottom":"0px","margin-left":"0px"};for(var i in t)o.getPropertyValue(i)!==t[i]&&(e.style[i]=t[i])},r=function(e){var o=e.parentNode;t(o),i(e),e.style.position="absolute",e.style.height="100%",e.style.width="auto",e.clientWidth>o.clientWidth?(e.style.top="0",e.style.marginTop="0",e.style.left="50%",e.style.marginLeft=e.clientWidth/-2+"px"):(e.style.width="100%",e.style.height="auto",e.style.left="0",e.style.marginLeft="0",e.style.top="50%",e.style.marginTop=e.clientHeight/-2+"px")},s=function(e){if(void 0===e)e=document.querySelectorAll("[data-object-fit]");else if(e&&e.nodeName)e=[e];else{if("object"!=typeof e||!e.length||!e[0].nodeName)return!1;e=e}for(var t=0;t0?r(e[t]):e[t].addEventListener("loadedmetadata",function(){r(this)})):e[t].complete?r(e[t]):e[t].addEventListener("load",function(){r(this)})}return!0};document.addEventListener("DOMContentLoaded",function(){s()}),window.addEventListener("resize",function(){s()}),window.objectFitPolyfill=s}}();var foyer_slide_bg_video_selector=".foyer-slide-background-video",foyer_yt_players={},foyer_yt_api_ready=!1;jQuery(document).ready(function(){foyer_slide_bg_video_load_youtube_api(),foyer_slide_bg_video_bind_display_loading_events(),foyer_slide_bg_video_bind_ticker_events()});var foyer_slide_bg_html5_video_selector=".foyer-slide-background-html5-video";jQuery(document).ready(function(){foyer_slide_bg_html5_video_bind_ticker_events()});var foyer_ticker_shutdown_status=!1,foyer_ticker_shutdown_callback,foyer_ticker_shutdown_callback_options,foyer_ticker_css_transition_duration=1.5,foyer_ticker_css_transition_duration_safe=foyer_ticker_css_transition_duration+.5;jQuery(document).ready(function(){jQuery(foyer_slides_selector).length&&(foyer_ticker_bind_events(),foyer_ticker_init())}); -------------------------------------------------------------------------------- /admin/class-foyer-admin-slide.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class Foyer_Admin_Slide { 14 | 15 | /** 16 | * Adds the channel editor meta box to the display admin page. 17 | * 18 | * @since 1.0.0 19 | * @since 1.3.1 Updated the slide_default_meta_box callback, after method was moved to Foyer_Admin_Slide_Format_Default. 20 | * @since 1.3.2 Changed method to static. 21 | * @since 1.4.0 Removed value for $meta_box_callback for default slide format, as this value is now defined in the 22 | * slide format properties, same as for the other slide formats. 23 | * Switched to a single metabox holding format and background selects and content. 24 | */ 25 | static function add_slide_editor_meta_boxes() { 26 | add_meta_box( 27 | 'foyer_slide_content', 28 | __( 'Slide content' , 'foyer' ), 29 | array( __CLASS__, 'slide_content_meta_box' ), 30 | Foyer_Slide::post_type_name, 31 | 'normal', 32 | 'low' 33 | ); 34 | } 35 | 36 | /** 37 | * Adds a Slide Format column to the Slides admin table, just after the title column. 38 | * 39 | * @since 1.0.0 40 | * @since 1.3.2 Changed method to static. 41 | * @since 1.5.1 Renamed column from 'Slide format' to 'Slide format, background'. 42 | * 43 | * @param array $columns The current columns. 44 | * @return array The new columns. 45 | */ 46 | static function add_slide_format_column( $columns ) { 47 | $new_columns = array(); 48 | 49 | foreach( $columns as $key => $title ) { 50 | $new_columns[$key] = $title; 51 | 52 | if ( 'title' == $key ) { 53 | // Add slides count column after the title column 54 | $new_columns['slide_format'] = __( 'Slide format, background', 'foyer' ); 55 | } 56 | } 57 | return $new_columns; 58 | } 59 | 60 | /** 61 | * Outputs the Slide Format column. 62 | * 63 | * @since 1.0.0 64 | * @since 1.3.2 Changed method to static. 65 | * @since 1.5.1 Added the slide background to the output. 66 | * 67 | * @param string $column The current column that needs output. 68 | * @param int $post_id The current display ID. 69 | * @return void 70 | */ 71 | static function do_slide_format_column( $column, $post_id ) { 72 | if ( 'slide_format' == $column ) { 73 | 74 | $slide = new Foyer_Slide( $post_id ); 75 | 76 | $format = Foyer_Slides::get_slide_format_by_slug( $slide->get_format() ); 77 | $background = Foyer_Slides::get_slide_background_by_slug( $slide->get_background() ); 78 | 79 | echo esc_html( $format['title'] ) . '
' . esc_html( $background['title'] ); 80 | } 81 | } 82 | 83 | /** 84 | * Localizes the JavaScript for the slide admin area. 85 | * 86 | * @since 1.0.0 87 | * @since 1.0.1 Escaped the output. 88 | * @since 1.1.3 Fixed a Javascript issue where adding an image to a slide was only possible when 89 | * the image was already in the media library. Removed 'photo' default as it is no 90 | * longer needed by our Javascript. 91 | * @since 1.3.1 Changed handle of script to {plugin_name}-admin. 92 | * @since 1.3.2 Changed method to static. 93 | * @since 1.4.0 Renamed slide_format_default to slide_image_defaults. 94 | * Added the slide formats backgrounds. 95 | * @since 1.6.0 Renamed slide_image_defaults to slide_file_defaults and added texts for different file types. 96 | * 97 | */ 98 | static function localize_scripts() { 99 | $slide_file_defaults = array( 100 | 'image' => array( 101 | 'text_select' => esc_html__( 'Select an image', 'foyer' ), 102 | 'text_use' => esc_html__( 'Use this image', 'foyer' ), 103 | ), 104 | 'application/pdf' => array( 105 | 'text_select' => esc_html__( 'Select a PDF', 'foyer' ), 106 | 'text_use' => esc_html__( 'Use this PDF', 'foyer' ), 107 | ), 108 | 'video' => array( 109 | 'text_select' => esc_html__( 'Select a video', 'foyer' ), 110 | 'text_use' => esc_html__( 'Use this video', 'foyer' ), 111 | ), 112 | ); 113 | wp_localize_script( Foyer::get_plugin_name() . '-admin', 'foyer_slide_file_defaults', $slide_file_defaults ); 114 | 115 | $slide_formats_backgrounds = Foyer_Slides::get_slide_formats_backgrounds(); 116 | wp_localize_script( Foyer::get_plugin_name() . '-admin', 'foyer_slide_formats_backgrounds', $slide_formats_backgrounds ); 117 | } 118 | 119 | /** 120 | * Removes the sample permalink from the Slide edit screen. 121 | * 122 | * @since 1.0.0 123 | * @since 1.3.2 Changed method to static. 124 | * 125 | * @param string $sample_permalink 126 | * @return string 127 | */ 128 | static function remove_sample_permalink( $sample_permalink ) { 129 | 130 | $screen = get_current_screen(); 131 | 132 | // Bail if not on Slide edit screen. 133 | if ( empty( $screen ) || Foyer_Slide::post_type_name != $screen->post_type ) { 134 | return $sample_permalink; 135 | } 136 | 137 | return ''; 138 | } 139 | 140 | /** 141 | * Saves all custom fields for a display. 142 | * 143 | * Triggered when a display is submitted from the display admin form. 144 | * 145 | * @since 1.0.0 146 | * @since 1.3.1 Updated the save_slide_default call, after method was moved to Foyer_Admin_Slide_Format_Default. 147 | * @since 1.3.2 Changed method to static. 148 | * @since 1.4.0 Removed call_user_func_array() for default slide format, as the callback is now defined in the 149 | * slide format properties, same as for the other slide formats. 150 | * Saves the slide background value, and invokes saving the background's fields through a callback. 151 | * 152 | * @param int $post_id The channel id. 153 | * @return void 154 | */ 155 | static function save_slide( $post_id ) { 156 | 157 | /* 158 | * We need to verify this came from our screen and with proper authorization, 159 | * because save_post can be triggered at other times. 160 | */ 161 | 162 | /* Check if our nonce is set */ 163 | if ( ! isset( $_POST[Foyer_Slide::post_type_name.'_nonce'] ) ) { 164 | return $post_id; 165 | } 166 | 167 | $nonce = $_POST[Foyer_Slide::post_type_name.'_nonce']; 168 | 169 | /* Verify that the nonce is valid */ 170 | if ( ! wp_verify_nonce( $nonce, Foyer_Slide::post_type_name ) ) { 171 | return $post_id; 172 | } 173 | 174 | /* If this is an autosave, our form has not been submitted, so we don't want to do anything */ 175 | if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { 176 | return $post_id; 177 | } 178 | 179 | /* Check the user's permissions */ 180 | if ( ! current_user_can( 'edit_post', $post_id ) ) { 181 | return $post_id; 182 | } 183 | 184 | if ( ! isset( $_POST['slide_format'] ) || ! isset( $_POST['slide_background'] ) ) { 185 | return $post_id; 186 | } 187 | 188 | /* Slide format */ 189 | $slide_format_slug = sanitize_title( $_POST['slide_format'] ); 190 | $slide_format = Foyer_Slides::get_slide_format_by_slug( $slide_format_slug ); 191 | 192 | /* Slide background */ 193 | $slide_background_slug = sanitize_title( $_POST['slide_background'] ); 194 | $slide_background = Foyer_Slides::get_slide_background_by_slug_for_slide_format( $slide_background_slug, $slide_format_slug ); 195 | 196 | if ( empty( $slide_format ) || empty( $slide_background ) ) { 197 | // Submitted slide format or slide background does not exist, bail 198 | return $post_id; 199 | } 200 | 201 | update_post_meta( $post_id, 'slide_format', $slide_format_slug ); 202 | 203 | if ( ! empty( $slide_format['save_post'] ) ) { 204 | call_user_func_array( $slide_format['save_post'], array( $post_id ) ); 205 | } 206 | 207 | update_post_meta( $post_id, 'slide_background', $slide_background_slug ); 208 | 209 | if ( ! empty( $slide_background['save_post'] ) ) { 210 | call_user_func_array( $slide_background['save_post'], array( $post_id ) ); 211 | } 212 | } 213 | 214 | /** 215 | * Outputs the content of the meta box holding all slide background choices. 216 | * 217 | * @since 1.4.0 218 | * 219 | * @param WP_Post $post The post object of the current slide. 220 | * @return void 221 | */ 222 | static function slide_background_meta_box( $post ) { 223 | 224 | wp_nonce_field( Foyer_Slide::post_type_name, Foyer_Slide::post_type_name.'_nonce' ); 225 | 226 | $slide = new Foyer_Slide( $post->ID ); 227 | 228 | ?> $slide_background_data ) { 232 | ?>ID ); 262 | 263 | ?>
264 | 265 | 267 | 268 |
269 |

270 | 278 |
279 | 280 |
281 |

282 | 289 |
290 |
291 | 292 | 293 |
$slide_format_data ) { 296 | 297 | ?>
298 |
299 |
300 |
301 |
302 | 303 | 304 |

305 | 306 | 307 | 308 |

309 | 310 | 311 | 312 | ID ) ) ); ?> 313 | 314 | 315 | 316 |
318 | 319 |
320 | 321 |
$slide_background_data ) { 324 | 325 | ?>
326 |
327 |
328 |
329 |
330 | 331 | 332 |

333 | 334 | 335 | 336 |

337 | 338 | 339 | 340 | ID ) ) ); ?> 341 | 342 | 343 |
345 | 346 |
$slide_format_data ) { 361 | if ( $stack == Foyer_Slides::slide_format_is_stack( $slide_format_key ) ) { 362 | 363 | ?> 12 | */ 13 | class Foyer_Admin_Display { 14 | 15 | /** 16 | * Adds Default Channel and Active Channel columns to the Displays admin table. 17 | * 18 | * Also removes the Date column. 19 | * 20 | * @since 1.0.0 21 | * @since 1.3.2 Changed method to static. 22 | * 23 | * @param array $columns The current columns. 24 | * @return array The new columns. 25 | */ 26 | static function add_channel_columns($columns) { 27 | unset($columns['date']); 28 | return array_merge($columns, 29 | array( 30 | 'default_channel' => __('Default channel', 'foyer'), 31 | 'active_channel' => __('Active channel', 'foyer'), 32 | ) 33 | ); 34 | } 35 | 36 | /** 37 | * Adds the channel editor meta box to the display admin page. 38 | * 39 | * @since 1.0.0 40 | * @since 1.3.2 Changed method to static. 41 | * @since 1.5.1 Added context to the translatable string 'Channel' to make translation easier. 42 | */ 43 | static function add_channel_editor_meta_box() { 44 | add_meta_box( 45 | 'foyer_channel_editor', 46 | _x( 'Channel', 'channel cpt', 'foyer' ), 47 | array( __CLASS__, 'channel_editor_meta_box' ), 48 | Foyer_Display::post_type_name, 49 | 'normal', 50 | 'high' 51 | ); 52 | } 53 | 54 | /** 55 | * Adds the channel scheduler meta box to the display admin page. 56 | * 57 | * @since 1.0.0 58 | * @since 1.3.2 Changed method to static. 59 | */ 60 | static function add_channel_scheduler_meta_box() { 61 | add_meta_box( 62 | 'foyer_channel_scheduler', 63 | __( 'Schedule temporary channel' , 'foyer' ), 64 | array( __CLASS__, 'channel_scheduler_meta_box' ), 65 | Foyer_Display::post_type_name, 66 | 'normal', 67 | 'high' 68 | ); 69 | } 70 | 71 | /** 72 | * Outputs the content of the channel editor meta box. 73 | * 74 | * @since 1.0.0 75 | * @since 1.0.1 Sanitized the output. 76 | * @since 1.3.2 Changed method to static. 77 | * 78 | * @param WP_Post $post The post object of the current display. 79 | */ 80 | static function channel_editor_meta_box( $post ) { 81 | 82 | wp_nonce_field( Foyer_Display::post_type_name, Foyer_Display::post_type_name.'_nonce' ); 83 | 84 | ob_start(); 85 | 86 | ?> 87 | 89 | 90 | 91 | 92 | 97 | 98 |
99 | 100 | 123 | 125 | 126 | 127 | 128 | 133 | 134 |
135 | 136 | get_active_channel() ) { 165 | _e( 'None', 'foyer' ); 166 | break; 167 | } 168 | 169 | $channel = new Foyer_Channel( $active_channel_id ); 170 | 171 | ?>ID ) ); 173 | ?>get_default_channel() ) { 182 | _e( 'None', 'foyer' ); 183 | break; 184 | } 185 | 186 | $channel = new Foyer_Channel( $default_channel_id ); 187 | 188 | ?>ID ) ); 190 | ?> 'Y-m-d H:i', 209 | 'duration' => 1 * 60 * 60, // one hour in seconds 210 | 'locale' => $language_parts[0], // locale formatted as 'en' instead of 'en-US' 211 | 'start_of_week' => get_option( 'start_of_week' ), 212 | ); 213 | 214 | /** 215 | * Filters the channel scheduler defaults. 216 | * 217 | * @since 1.0.0 218 | * 219 | * @param array $defaults The current defaults to be used in the channel scheduler. 220 | */ 221 | return apply_filters( 'foyer/channel_scheduler/defaults', $defaults ); 222 | } 223 | 224 | /** 225 | * Gets the HTML that lists the default channel in the channel editor. 226 | * 227 | * @since 1.0.0 228 | * @since 1.0.1 Escaped and sanitized the output. 229 | * @since 1.2.3 Changed the list of available channels from limited to unlimited. 230 | * @since 1.3.2 Changed method to static. 231 | * 232 | * @param WP_Post $post 233 | * @return string $html The HTML that lists the default channel in the channel editor. 234 | */ 235 | static function get_default_channel_html( $post ) { 236 | 237 | $display = new Foyer_Display( $post ); 238 | $default_channel = $display->get_default_channel(); 239 | 240 | ob_start(); 241 | 242 | ?> 243 | 244 | 245 | 248 | 249 | 250 | 265 | 266 | 267 | get_schedule(); 291 | 292 | if ( !empty( $schedule ) ) { 293 | $scheduled_channel = $schedule[0]; 294 | } 295 | 296 | $channel_scheduler_defaults = self::get_channel_scheduler_defaults(); 297 | 298 | ob_start(); 299 | 300 | ?> 301 | 302 | 303 | 306 | 307 | 308 | 323 | 324 | 325 | 326 | 327 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 340 | 341 | 342 | 343 | 344 | 345 | $foyer_channel_editor_scheduled_channel, 481 | 'start' => $start, 482 | 'end' => $end, 483 | ); 484 | 485 | add_post_meta( $display_id, 'foyer_display_schedule', $schedule, false ); 486 | } 487 | } 488 | -------------------------------------------------------------------------------- /public/css/foyer-public.css: -------------------------------------------------------------------------------- 1 | body.single-foyer_display.admin-bar, 2 | body.single-foyer_channel.admin-bar, 3 | body.single-foyer_slide.admin-bar { 4 | display: -webkit-box; 5 | display: -ms-flexbox; 6 | display: flex; 7 | -webkit-box-align: center; 8 | -ms-flex-align: center; 9 | align-items: center; 10 | height: auto; 11 | background-color: #555; 12 | } 13 | .foyer-preview-9-16, 14 | .foyer-preview-16-9 { 15 | margin: 0 auto; 16 | display: block; 17 | border: none; 18 | -webkit-transition: .5s all ease; 19 | transition: .5s all ease; 20 | margin-top: -45px; 21 | } 22 | @media screen and (max-width: 782px) { 23 | .foyer-preview-9-16, 24 | .foyer-preview-16-9 { 25 | margin-top: -45px; 26 | } 27 | } 28 | .foyer-preview-9-16 { 29 | width: calc(54vh - 43.3125px); 30 | height: calc(96vh - 77px); 31 | } 32 | @media screen and (max-width: 782px) { 33 | .foyer-preview-9-16 { 34 | width: calc(54vh - 51.1875px); 35 | height: calc(96vh - 91px); 36 | } 37 | } 38 | .foyer-preview-16-9 { 39 | width: calc(96vh - 77px); 40 | height: calc(54vh - 43.3125px); 41 | } 42 | @media screen and (max-width: 782px) { 43 | .foyer-preview-16-9 { 44 | width: calc(96vh - 91px); 45 | height: calc(54vh - 51.1875px); 46 | } 47 | } 48 | .foyer-preview-actions { 49 | position: fixed; 50 | z-index: 999; 51 | bottom: 0; 52 | height: 45px; 53 | border-top: 1px solid #eee; 54 | background: #eee; 55 | width: 100%; 56 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 57 | font-size: 13px; 58 | font-weight: 400; 59 | line-height: 32px; 60 | -webkit-font-smoothing: subpixel-antialiased; 61 | -moz-osx-font-smoothing: auto; 62 | text-align: center; 63 | } 64 | .foyer-preview-actions div { 65 | display: inline-block; 66 | cursor: pointer; 67 | border: none; 68 | height: 44px; 69 | margin: 0; 70 | padding: 4px 8px; 71 | -webkit-box-shadow: none; 72 | box-shadow: none; 73 | border-bottom: 4px solid transparent; 74 | -webkit-transition: 0.15s color ease-in-out, 0.15s background-color ease-in-out, 0.15s border-color ease-in-out; 75 | transition: 0.15s color ease-in-out, 0.15s background-color ease-in-out, 0.15s border-color ease-in-out; 76 | font: inherit; 77 | color: #72777c; 78 | outline: none; 79 | } 80 | .foyer-preview-actions div:hover { 81 | background-color: #fff; 82 | color: #0073aa; 83 | } 84 | .foyer-preview-actions div:hover.active { 85 | border-color: #0073aa; 86 | } 87 | .foyer-preview-actions div.active { 88 | border-color: #23282d; 89 | color: #23282d; 90 | } 91 | .foyer-preview-actions div.active:hover { 92 | color: #0073aa; 93 | border-color: #0073aa; 94 | } 95 | body.single-foyer_display, 96 | body.single-foyer_channel, 97 | body.single-foyer_slide { 98 | margin: 0; 99 | padding: 0; 100 | width: 100vw; 101 | height: 100vh; 102 | max-width: none; 103 | max-height: none; 104 | -webkit-font-smoothing: antialiased; 105 | -moz-font-smoothing: antialiased; 106 | -o-font-smoothing: antialiased; 107 | -moz-osx-font-smoothing: grayscale; 108 | -webkit-text-size-adjust: 100%; 109 | -ms-text-size-adjust: 100%; 110 | -webkit-box-sizing: border-box; 111 | box-sizing: border-box; 112 | } 113 | body.single-foyer_display *, 114 | body.single-foyer_channel *, 115 | body.single-foyer_slide * { 116 | -webkit-box-sizing: border-box; 117 | box-sizing: border-box; 118 | } 119 | body.single-foyer_display:not(.custom-background-image):before, 120 | body.single-foyer_channel:not(.custom-background-image):before, 121 | body.single-foyer_slide:not(.custom-background-image):before, 122 | body.single-foyer_display:not(.custom-background-image):after, 123 | body.single-foyer_channel:not(.custom-background-image):after, 124 | body.single-foyer_slide:not(.custom-background-image):after { 125 | display: none; 126 | } 127 | .foyer-display, 128 | .foyer-channel, 129 | .foyer-slides { 130 | width: 100%; 131 | height: 100%; 132 | } 133 | .foyer-slide { 134 | overflow: hidden; 135 | } 136 | .foyer-transition-fade .foyer-slides { 137 | position: relative; 138 | overflow: hidden; 139 | width: 100%; 140 | z-index: 1; 141 | } 142 | .foyer-transition-fade .foyer-slides .foyer-slide { 143 | width: 100%; 144 | position: absolute; 145 | left: 100%; 146 | top: 0; 147 | -webkit-backface-visibility: hidden; 148 | /* fixes a Chrome opacity transition bug */ 149 | opacity: 0; 150 | -webkit-transition: opacity 1.5s ease, left 0s ease 1.5s; 151 | transition: opacity 1.5s ease, left 0s ease 1.5s; 152 | } 153 | .foyer-transition-fade .foyer-slides .foyer-slide:first-child { 154 | position: relative; 155 | opacity: 0; 156 | left: 0; 157 | z-index: 2; 158 | } 159 | .foyer-transition-fade .foyer-slides .foyer-slide.active { 160 | opacity: 1; 161 | left: 0; 162 | z-index: 3; 163 | -webkit-transition: left 0s, opacity 1.5s ease; 164 | transition: left 0s, opacity 1.5s ease; 165 | } 166 | .foyer-transition-slide .foyer-slides { 167 | position: relative; 168 | overflow: hidden; 169 | width: 100%; 170 | z-index: 1; 171 | } 172 | .foyer-transition-slide .foyer-slides .foyer-slide { 173 | width: 100%; 174 | position: absolute; 175 | left: -100%; 176 | top: 0; 177 | bottom: 0; 178 | opacity: 0; 179 | -webkit-transition: left 1.5s ease, opacity 0s ease 1.5s; 180 | transition: left 1.5s ease, opacity 0s ease 1.5s; 181 | } 182 | .foyer-transition-slide .foyer-slides .foyer-slide.active { 183 | left: 0; 184 | opacity: 1; 185 | z-index: 2; 186 | -webkit-transition: opacity 0s, left 1.5s ease; 187 | transition: opacity 0s, left 1.5s ease; 188 | } 189 | .foyer-transition-slide .foyer-slides .foyer-slide.next { 190 | left: 100%; 191 | opacity: 1; 192 | z-index: 2; 193 | -webkit-transition: left 0s ease, opacity 0s ease; 194 | transition: left 0s ease, opacity 0s ease; 195 | } 196 | .foyer-transition-none .foyer-slides { 197 | position: relative; 198 | overflow: hidden; 199 | width: 100%; 200 | z-index: 1; 201 | } 202 | .foyer-transition-none .foyer-slides .foyer-slide { 203 | display: none; 204 | } 205 | .foyer-transition-none .foyer-slides .foyer-slide.active { 206 | display: block; 207 | } 208 | html { 209 | font-size: 100% !important; 210 | font-size: 1.48148148vmin !important; 211 | } 212 | .foyer-slide { 213 | width: 100%; 214 | height: 100%; 215 | background-color: #fff; 216 | position: relative; 217 | z-index: 1; 218 | overflow: hidden; 219 | } 220 | .foyer-slide .foyer-slide-field { 221 | color: #000; 222 | font-size: 2rem; 223 | line-height: 1.2; 224 | } 225 | .foyer-slide .foyer-slide-field.foyer-slide-field-title { 226 | font-size: 5rem; 227 | font-weight: bold; 228 | margin-bottom: 1rem; 229 | } 230 | .foyer-slide .foyer-slide-field.foyer-slide-field-pretitle, 231 | .foyer-slide .foyer-slide-field.foyer-slide-field-subtitle { 232 | font-size: 3rem; 233 | font-weight: bold; 234 | margin-bottom: 1rem; 235 | } 236 | .foyer-slide .foyer-slide-field.foyer-slide-field-date { 237 | font-size: 3rem; 238 | margin-bottom: 1rem; 239 | } 240 | .foyer-slide .foyer-slide-field.foyer-slide-field-content > *:last-child { 241 | margin-bottom: 0; 242 | } 243 | .foyer-slide .foyer-slide-background { 244 | position: absolute; 245 | top: 0; 246 | bottom: 0; 247 | left: 0; 248 | right: 0; 249 | z-index: -1; 250 | overflow: hidden; 251 | } 252 | .foyer-slide.foyer-slide-iframe iframe { 253 | width: 100%; 254 | height: 100%; 255 | border: none; 256 | margin: 0; 257 | padding: 0; 258 | } 259 | .foyer-slide.foyer-slide-pdf figure { 260 | margin: 0; 261 | } 262 | .foyer-slide.foyer-slide-pdf figure img { 263 | width: 100%; 264 | height: 100%; 265 | -o-object-fit: contain; 266 | object-fit: contain; 267 | } 268 | .foyer-slide.foyer-slide-post .inner { 269 | display: -webkit-box; 270 | display: -ms-flexbox; 271 | display: flex; 272 | width: 100%; 273 | height: 100%; 274 | } 275 | .foyer-slide.foyer-slide-post .inner figure, 276 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields { 277 | -webkit-box-flex: 0; 278 | -ms-flex: 0 0 auto; 279 | flex: 0 0 auto; 280 | width: auto; 281 | height: auto; 282 | } 283 | .foyer-slide.foyer-slide-post .inner figure { 284 | margin: 0; 285 | } 286 | .foyer-slide.foyer-slide-post .inner figure img { 287 | width: 100%; 288 | height: 100%; 289 | -o-object-fit: cover; 290 | object-fit: cover; 291 | } 292 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields { 293 | display: -webkit-box; 294 | display: -ms-flexbox; 295 | display: flex; 296 | -webkit-box-orient: vertical; 297 | -webkit-box-direction: normal; 298 | -ms-flex-direction: column; 299 | flex-direction: column; 300 | -webkit-box-pack: center; 301 | -ms-flex-pack: center; 302 | justify-content: center; 303 | padding: 4vmin; 304 | } 305 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields .foyer-slide-field-title span, 306 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields .foyer-slide-field-date span, 307 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields .foyer-slide-field-content { 308 | line-height: 1.5; 309 | padding: 0.5rem 1rem; 310 | background-color: rgba(255, 255, 255, 0.8); 311 | -webkit-box-decoration-break: clone; 312 | box-decoration-break: clone; 313 | } 314 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields .foyer-slide-field-date span { 315 | line-height: 1.7; 316 | } 317 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields .foyer-slide-field-content { 318 | padding: 1.5rem 1rem; 319 | } 320 | @media (min-aspect-ratio: 1/1) { 321 | .foyer-slide.foyer-slide-post .inner { 322 | -webkit-box-orient: horizontal; 323 | -webkit-box-direction: normal; 324 | -ms-flex-direction: row; 325 | flex-direction: row; 326 | } 327 | .foyer-slide.foyer-slide-post .inner .foyer-slide-fields { 328 | width: 66.66666667%; 329 | } 330 | .foyer-slide.foyer-slide-post .inner figure, 331 | .foyer-slide.foyer-slide-post .inner figure + .foyer-slide-fields { 332 | width: 50%; 333 | } 334 | } 335 | @media (max-aspect-ratio: 1/1) { 336 | .foyer-slide.foyer-slide-post .inner { 337 | -webkit-box-orient: vertical; 338 | -webkit-box-direction: normal; 339 | -ms-flex-direction: column; 340 | flex-direction: column; 341 | -webkit-box-pack: end; 342 | -ms-flex-pack: end; 343 | justify-content: flex-end; 344 | } 345 | .foyer-slide.foyer-slide-post .inner figure, 346 | .foyer-slide.foyer-slide-post .inner figure + .foyer-slide-fields { 347 | height: 50%; 348 | } 349 | } 350 | .foyer-slide.foyer-slide-production .foyer-slide-fields { 351 | position: absolute; 352 | bottom: 0; 353 | left: 0; 354 | right: 0; 355 | padding: 2vmin 4vmin; 356 | background-color: rgba(255, 255, 255, 0.8); 357 | } 358 | .foyer-slide.foyer-slide-recent-posts .inner { 359 | display: -webkit-box; 360 | display: -ms-flexbox; 361 | display: flex; 362 | width: 100%; 363 | height: 100%; 364 | } 365 | .foyer-slide.foyer-slide-recent-posts .inner figure, 366 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields { 367 | -webkit-box-flex: 0; 368 | -ms-flex: 0 0 auto; 369 | flex: 0 0 auto; 370 | width: auto; 371 | height: auto; 372 | } 373 | .foyer-slide.foyer-slide-recent-posts .inner figure { 374 | margin: 0; 375 | } 376 | .foyer-slide.foyer-slide-recent-posts .inner figure img { 377 | width: 100%; 378 | height: 100%; 379 | -o-object-fit: cover; 380 | object-fit: cover; 381 | } 382 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields { 383 | display: -webkit-box; 384 | display: -ms-flexbox; 385 | display: flex; 386 | -webkit-box-orient: vertical; 387 | -webkit-box-direction: normal; 388 | -ms-flex-direction: column; 389 | flex-direction: column; 390 | -webkit-box-pack: center; 391 | -ms-flex-pack: center; 392 | justify-content: center; 393 | padding: 4vmin; 394 | } 395 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields .foyer-slide-field-title span, 396 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields .foyer-slide-field-date span, 397 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields .foyer-slide-field-content { 398 | line-height: 1.5; 399 | padding: 0.5rem 1rem; 400 | background-color: rgba(255, 255, 255, 0.8); 401 | -webkit-box-decoration-break: clone; 402 | box-decoration-break: clone; 403 | } 404 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields .foyer-slide-field-date span { 405 | line-height: 1.7; 406 | } 407 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields .foyer-slide-field-content { 408 | padding: 1.5rem 1rem; 409 | } 410 | @media (min-aspect-ratio: 1/1) { 411 | .foyer-slide.foyer-slide-recent-posts .inner { 412 | -webkit-box-orient: horizontal; 413 | -webkit-box-direction: normal; 414 | -ms-flex-direction: row; 415 | flex-direction: row; 416 | } 417 | .foyer-slide.foyer-slide-recent-posts .inner .foyer-slide-fields { 418 | width: 66.66666667%; 419 | } 420 | .foyer-slide.foyer-slide-recent-posts .inner figure, 421 | .foyer-slide.foyer-slide-recent-posts .inner figure + .foyer-slide-fields { 422 | width: 50%; 423 | } 424 | } 425 | @media (max-aspect-ratio: 1/1) { 426 | .foyer-slide.foyer-slide-recent-posts .inner { 427 | -webkit-box-orient: vertical; 428 | -webkit-box-direction: normal; 429 | -ms-flex-direction: column; 430 | flex-direction: column; 431 | -webkit-box-pack: end; 432 | -ms-flex-pack: end; 433 | justify-content: flex-end; 434 | } 435 | .foyer-slide.foyer-slide-recent-posts .inner figure, 436 | .foyer-slide.foyer-slide-recent-posts .inner figure + .foyer-slide-fields { 437 | height: 50%; 438 | } 439 | } 440 | .foyer-slide.foyer-slide-text .inner { 441 | display: -webkit-box; 442 | display: -ms-flexbox; 443 | display: flex; 444 | width: 100%; 445 | height: 100%; 446 | } 447 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields { 448 | -webkit-box-flex: 0; 449 | -ms-flex: 0 0 auto; 450 | flex: 0 0 auto; 451 | width: auto; 452 | height: auto; 453 | } 454 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields { 455 | display: -webkit-box; 456 | display: -ms-flexbox; 457 | display: flex; 458 | -webkit-box-orient: vertical; 459 | -webkit-box-direction: normal; 460 | -ms-flex-direction: column; 461 | flex-direction: column; 462 | -webkit-box-pack: center; 463 | -ms-flex-pack: center; 464 | justify-content: center; 465 | padding: 4vmin; 466 | } 467 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-pretitle span, 468 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-title span, 469 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-subtitle span, 470 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-content { 471 | line-height: 1.5; 472 | padding: 0.5rem 1rem; 473 | background-color: rgba(255, 255, 255, 0.8); 474 | -webkit-box-decoration-break: clone; 475 | box-decoration-break: clone; 476 | } 477 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-pretitle span, 478 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-subtitle span { 479 | line-height: 1.7; 480 | } 481 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields .foyer-slide-field-content { 482 | padding: 1.5rem 1rem; 483 | } 484 | @media (min-aspect-ratio: 1/1) { 485 | .foyer-slide.foyer-slide-text .inner { 486 | -webkit-box-orient: horizontal; 487 | -webkit-box-direction: normal; 488 | -ms-flex-direction: row; 489 | flex-direction: row; 490 | } 491 | .foyer-slide.foyer-slide-text .inner .foyer-slide-fields { 492 | width: 66.66666667%; 493 | } 494 | } 495 | @media (max-aspect-ratio: 1/1) { 496 | .foyer-slide.foyer-slide-text .inner { 497 | -webkit-box-orient: vertical; 498 | -webkit-box-direction: normal; 499 | -ms-flex-direction: column; 500 | flex-direction: column; 501 | -webkit-box-pack: end; 502 | -ms-flex-pack: end; 503 | justify-content: flex-end; 504 | } 505 | } 506 | .foyer-slide.foyer-slide-upcoming-productions .foyer-slide-fields { 507 | position: absolute; 508 | bottom: 0; 509 | left: 0; 510 | right: 0; 511 | padding: 2vmin 4vmin; 512 | background-color: rgba(255, 255, 255, 0.8); 513 | } 514 | .foyer-slide-background.foyer-slide-background-image figure, 515 | .foyer-slide-background.foyer-slide-background-default figure { 516 | margin: 0; 517 | width: 100%; 518 | height: 100%; 519 | } 520 | .foyer-slide-background.foyer-slide-background-image figure img, 521 | .foyer-slide-background.foyer-slide-background-default figure img { 522 | width: 100%; 523 | height: 100%; 524 | -o-object-fit: cover; 525 | object-fit: cover; 526 | } 527 | .foyer-slide-background.foyer-slide-background-video iframe { 528 | position: absolute; 529 | top: 0; 530 | right: 0; 531 | bottom: 0; 532 | left: 0; 533 | margin: auto; 534 | max-width: none; 535 | } 536 | .foyer-slide-background.foyer-slide-background-html5-video video { 537 | width: 100%; 538 | height: 100%; 539 | -o-object-fit: cover; 540 | object-fit: cover; 541 | } 542 | --------------------------------------------------------------------------------