UPDATE:It’s now on Github.
When the president of the Chicago campus of The Chicago School of Professional Psychology asked for flatscreen televisions to be hung by each of the elevators and in gathering spaces, most people thought the difficult part would be getting a good price on the TVs.
You won’t be able to afford digital signage technology.
The school is also host to an international institute that focuses on marketing messages; specifically digital signage. They were thrilled that the school was going to jump onto the technology, but were stuck on the cost of existing platforms.
The real challenge was dropped on my plate at the end of a status meeting. I was pumped!
“The flatscreens are happening. Can you design a layout? And make it sustainable to manage?”
I turned to WordPress
But I knew it needed a strict structure, people couldn’t be expected to adhere on their own.
The entire screen is filled with carousel that, using @malsup’s jQuery Cycle Plugin, displays a single post for 18 seconds at a time. There’s also a dock at the bottom of the page with four dynamic sidebars that are driven by jCarouselLite.
- the More Fields plugin allowed me to add the specific fields I would need:
- the Weather plugin could be customized for Chicago (more details on this later)
- the school uses Google calendars, so the ICS Calendar plugin pulled in the ICS feed for a scrolling list of events
- for a little local color, the KB Advanced RSS plugin scrolled the great events listed on GapersBlock
- the QR Code Tag plugin automatically generates a QR code for a specified URL
- because the design breaks on smaller screens, the WordPress Mobile Edition plugin allowed for mobile visitors to not feel left out
- since none of the events are evergreen, the Post Expirator plugin does just what it says
- I also built a simple current time plugin (more on this later)
Let’s start with functions.php
The first is fairly straightforward about setting up five sidebars. Yes, five. In order to get the time and weather to not remain the same from when the browser started in the morning, the sidebar sidebar doesn’t appear on the page directly, but appears in an iFramed house of mirrors.1
We’re just registering new sidebars, naming them, giving the title an H3 and a link.
if ( function_exists('register_sidebar') )
register_sidebar(array('name'=>'sidebar',
'before_widget' => '<div>',
'after_widget' => '</div>',
'before_title' => '<h3><a href="http://www.weather.com/weather/today/Chicago+IL+USIL0225?lswe=Chicago,%20IL">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockLeft',
'before_widget' => '<div>',
'after_widget' => '</div>',
'before_title' => '<h3><a href="http://www.weather.com/weather/today/Chicago+IL+USIL0225?lswe=Chicago,%20IL">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockCenter',
'before_widget' => '',
'after_widget' => '',
'before_title' => '<h3><a href="http://ego.thechicagoschool.edu">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockRight',
'before_widget' => '',
'after_widget' => '',
'before_title' => '<h3><a href="http://gapersblock.com/" target="_blank">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockFarRight',
'before_widget' => '<div>',
'after_widget' => '</div>',
'before_title' => '<h3><a href="http://www.thechicagoschool.edu/content.cfm/academic_calendar" target="_blank">',
'after_title' => '</a></h3>',
));
After the sidebars are registered, we want to get rid of WordPress’ pesky automatic adding of paragraphs to widgets.
remove_filter ('the_content', 'wpautop');
Finally, we need to be able to get all of the data entered into those additional structured fields
function get_custom_field_value($szKey, $bPrint = false) {
global $post;
$szValue = get_post_meta($post->ID, $szKey, true);
if ( $bPrint == false ) return $szValue; else echo $szValue;
}
We’re left with this as functions.php
<?php
if ( function_exists('register_sidebar') )
register_sidebar(array('name'=>'sidebar',
'before_widget' => '<div>',
'after_widget' => '</div>',
'before_title' => '<h3><a href="http://www.weather.com/weather/today/Chicago+IL+USIL0225?lswe=Chicago,%20IL">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockLeft',
'before_widget' => '<div>',
'after_widget' => '</div>',
'before_title' => '<h3><a href="http://www.weather.com/weather/today/Chicago+IL+USIL0225?lswe=Chicago,%20IL">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockCenter',
'before_widget' => '',
'after_widget' => '',
'before_title' => '<h3><a href="http://ego.thechicagoschool.edu">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockRight',
'before_widget' => '',
'after_widget' => '',
'before_title' => '<h3><a href="http://gapersblock.com/" target="_blank">',
'after_title' => '</a></h3>',
));
register_sidebar(array('name' => 'DockFarRight',
'before_widget' => '<div>',
'after_widget' => '</div>',
'before_title' => '<h3><a href="http://www.thechicagoschool.edu/content.cfm/academic_calendar" target="_blank">',
'after_title' => '</a></h3>',
));
remove_filter ('the_content', 'wpautop');
function get_custom_field_value($szKey, $bPrint = false) {
global $post;
$szValue = get_post_meta($post->ID, $szKey, true);
if ( $bPrint == false ) return $szValue; else echo $szValue;
}
?>
Next, tackle header.php
This content would be changing regularly and needed to appear fresh as close to immediately as possible, so I added a meta refresh on every hour. Also, a meta nocache.
<meta http-equiv="refresh" content="3600">
<meta http-equiv="pragma" content="nocache">
jQuery is called from Google, and jQuery Cycle Plugin and jCarouselLite are called immediately after.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/scripts/jquery.cycle.all.js"></script>
<script src="<?php bloginfo('stylesheet_directory'); ?>/scripts/jcarousellite_1.0.1c4.js" type="text/javascript"></script>
Next, the settings for the main windown and the three scrolling sidebars on the dock are set.
<script type="text/javascript">
$(document).ready(function(){
$('#myslides').cycle({
fx: 'fade',
speed: 1000,
timeout: 18000
});
$(".scroll").jCarouselLite({
vertical: true,
hoverPause:false,
visible: 1,
auto:9000,
speed:500
});
$(".scroll2").jCarouselLite({
vertical: true,
hoverPause:false,
visible: 2,
auto:11000,
speed:500
});
$(".scroll3").jCarouselLite({
vertical: true,
hoverPause:false,
visible: 2,
auto:7000,
speed:500
});
});
</script>
That leaves us with this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="refresh" content="3600">
<meta http-equiv="pragma" content="nocache">
<title><?php bloginfo('name'); ?></title>
<meta name="description" content="<?php bloginfo('description'); ?>" />
<link rel="stylesheet" type="text/css" href="<?php bloginfo('stylesheet_url'); ?>" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="<?php bloginfo('stylesheet_directory'); ?>/scripts/jquery.cycle.all.js"></script>
<script src="<?php bloginfo('stylesheet_directory'); ?>/scripts/jcarousellite_1.0.1c4.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#myslides').cycle({
fx: 'fade',
speed: 1000,
timeout: 18000
});
$(".scroll").jCarouselLite({
vertical: true,
hoverPause:false,
visible: 1,
auto:9000,
speed:500
});
$(".scroll2").jCarouselLite({
vertical: true,
hoverPause:false,
visible: 2,
auto:11000,
speed:500
});
$(".scroll3").jCarouselLite({
vertical: true,
hoverPause:false,
visible: 2,
auto:7000,
speed:500
});
});
</script>
<?php wp_head() ?>
</head>
<body>
Home.php is next
I was on a real home.php kick at the time, but there’s no reason why index.php wouldn’t work for this as well. It’s probably smarter that way anyway.
First things first; call header.php
<?php get_header() ?>
Next, the big part. We’ll build out the slideshow. Get the posts, order them randomly and call the background color field to set the class for the wrapper.
<div id="myslides">
<?php query_posts("orderby=rand"); $i = 1; ?>
<?php while (have_posts()) : the_post(); ?>
<div class="<?php $key="background"; echo get_post_meta($post->ID, $key, true); ?>">
Next, call the post title, subhead field and image field. Call the image alignment field to set the class of the image. Finally, call the content of the post
<h1><?php the_title() ?></h1> <h2><?php $key="subhead"; echo get_post_meta($post->ID, $key, true); ?></h2> <p><img src="<?php $key="image"; echo get_post_meta($post->ID, $key, true); ?>" class="<?php $key="imagealign"; echo get_post_meta($post->ID, $key, true); ?>" /> <?php the_content(); ?></p>
Now, the fun part—create the QR code on the fly, by calling the web address field.
<p class="url"> <img src="<?php $key="webaddress"; global $qrcodetag; echo $qrcodetag->getQrCodeUrl(get_post_meta($post->ID, $key, true),248,'UTF-8','L',4,0); ?>" />
Tidy everything up.
</div><!--.container-->
</div><!--color-->
<?php endwhile; ?>
</div><!--#myslides-->
Now, on to the pseudo dock, where we have a little location message and call our sidebars.
<div id="dock">
<a href="http://ego.thechicagoschool.edu/" class="youarehere">The Chicago School, Chicago campus</a>
<div class="dockleft">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockLeft)) : ?>
<?php endif; ?>
</div> <!-- .dockleft -->
<div class="dockcenter">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockCenter)) : ?>
<?php endif; ?>
</div> <!-- .dockcenter -->
<div class="dockright">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockRight)) : ?>
<?php endif; ?>
</div> <!-- .dockright -->
<div class="dockfarright">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockFarRight)) : ?>
<?php endif; ?>
</div> <!-- .dockfarright -->
</div> <!-- #dock -->
That leaves us with this for the home.php or index.php file
<?php get_header() ?>
<div id="myslides">
<?php query_posts("orderby=rand"); $i = 1; ?>
<?php while (have_posts()) : the_post(); ?>
<div class="<?php $key="background"; echo get_post_meta($post->ID, $key, true); ?>">
<div class="container">
<h1><?php the_title() ?></h1>
<h2><?php $key="subhead"; echo get_post_meta($post->ID, $key, true); ?></h2>
<p><img src="<?php $key="image"; echo get_post_meta($post->ID, $key, true); ?>" class="<?php $key="imagealign"; echo get_post_meta($post->ID, $key, true); ?>" />
<?php the_content(); ?></p>
<p class="url">
<img src="<?php $key="webaddress";
global $qrcodetag;
echo $qrcodetag->getQrCodeUrl(get_post_meta($post->ID, $key, true),248,'UTF-8','L',4,0);
?>" />
</div><!--.container-->
</div><!--color-->
<?php endwhile; ?>
</div><!--#myslides-->
<div id="dock">
<a href="http://ego.thechicagoschool.edu/" class="youarehere"><img class="ted" src="http://full/path/to/wp-content/uploads/Ted-Rubenstein1.jpg" /> Dr. Ted Rubenstein, 1964-2010</a>
<div class="dockleft">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockLeft)) : ?>
<?php endif; ?>
</div> <!-- .dockleft -->
<div class="dockcenter">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockCenter)) : ?>
<?php endif; ?>
</div> <!-- .dockcenter -->
<div class="dockright">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockRight)) : ?>
<?php endif; ?>
</div> <!-- .dockright -->
<div class="dockfarright">
<?php if(function_exists('dynamic_sidebar') && dynamic_sidebar(DockFarRight)) : ?>
<?php endif; ?>
</div> <!-- .dockfarright -->
</div> <!-- #dock -->
<?php get_footer() ?>
Current Time plugin
After looking and looking for a current time plugin that displayed exactly how I needed, I gave up and decided to write my own simple plugin for it. Look up your PHP timezone, and you’ll be all set.
<?php
/*
Plugin Name: Current Time
Plugin URI: http://nathangjones.com/
Description: Current Time WordPress Plugin
Author: nate jones
Version: 1
Author URI: http://nathangjones.com/
*/
function currentTime()
{
date_default_timezone_set('America/Chicago');
$time = date("g:i a");
$date = date("M j");
echo '<span class="time">';
echo $time;
echo '</span>';
echo '<br />';
echo '<span class="date">';
echo $date;
echo '</span>';
}
function widget_currentTime($args) {
extract($args);
echo $before_widget;
echo $before_title;?><?php echo $after_title;
currentTime();
echo $after_widget;
}
function currentTime_init()
{
register_sidebar_widget(__('Current Time'), 'widget_currentTime');
}
add_action("plugins_loaded", "currentTime_init");
?>
iFrame house of mirrors
As I mentioned before, displaying weather and time wasn’t a big deal. The big deal was that they’d only be accurate for the first minute of the day. I’m sure there’s a more elegant way to conduct this business, I was just stumped and found this to work for me.
Enter the house of mirrors
We already created the sidebar, but it’s just not displayed on the screen. So we’ll create weather.html and iFrame in that sidebar. Then we’ll iframe weather.html in our dock, and set it to refresh every minute. Unnecessarily complicated, no? First, let’s call the stylesheet and jQuery
<link rel="stylesheet" type="text/css" href="full/path/to/style.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
Next, for a hint of simplicity, we’ll duplicate the same DIVs that appear in the WordPress site.
<dock id="dockleft">
<div>
<div class="textwidget">
<iframe src="http://full/path/to/left-dock/" scrolling="no" height="100%" widht="100%" style="height:100%; width:100%; background:transparent; border:none;"></iframe>
</div>
</div>
</div>
Finally, to make the incessant refreshing of content appear a little less obvious and more refined, let’s ease it in and out
<script>
var refreshId = setInterval(function()
{
$('#dockleft').fadeOut("fast").load('http://full/path/to/left-dock/').fadeIn("fast");
}, 15000);
</script>
That leaves us here for weather.html
<html>
<head>
<link rel="stylesheet" type="text/css" href="http://full/path/to/style.css" />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js" type="text/javascript"></script>
<script>
var refreshId = setInterval(function()
{
$('#dockleft').fadeOut("fast").load('http://full/path/to/left-dock/').fadeIn("fast");
}, 15000);
</script>
</head>
<body>
<dock id="dockleft">
<div>
<div class="textwidget">
<iframe src="http://full/path/to/left-dock/" scrolling="no" height="100%" widht="100%" style="height:100%; width:100%; background:transparent; border:none;"></iframe>
</div>
</div>
</div>
</body>
Footer
Nothing to see here. Just closing up the wrapper
<div class="footer">
<?php wp_footer() ?>
</div><!-- footer -->
</div><!-- wrapper -->
</body>
</html>
Placing the widgets into their respective sidebars
Drag the Weather and Current Time widgets into the sidebar sidebar. Then a text widget into the DockLeft sidebar to iframe in weather.html
<iframe src="http://full/path/to/weather.html" scrolling="no" height="100%" widht="100%" style="height:100%; width:100%; background:transparent;"></iframe>
Finally, some style
CSS is my favorite thing to do. It’s how I decompress and relax.
First the architecture, with one tiny trick. The TVs would be using Chrome to display the site in full-screen. The only problem was that they automatically put the cursor dead-center on the screen, which is a sure give away that it’s a website. So we replace the cursor with an image; a 98% transparent PNG.
html{
height:100%;
margin:0;
padding:0;
width:100%;
background:transparent;
}
* {
margin:0;
padding:0;
}
a:link, a:visited, a:hover, a:active{
outline:none;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
}
body{
padding:0;
height:100%;
width:100%;
background:transparent;
text-align:left;
overflow:hidden;
cursor: url(images/blank.png), default;
}
Next, the fonts and content.
@font-face {
font-family: 'TradeGothicLTStdLight';
src: url('fonts/TradeGothicLTStd-Light.eot');
src: local('fonts/Trade Gothic LT Std'), local('fonts/TradeGothicLTStd-Light'), url('fonts/TradeGothicLTStd-Light.woff') format('woff'), url('fonts/TradeGothicLTStd-Light.ttf') format('truetype');
}
@font-face {
font-family: 'TradeGothicLTStdRegular';
src: url('fonts/TradeGothicLTStd.eot');
src: local('fonts/Trade Gothic LT Std'), local('fonts/TradeGothicLTStd'), url('fonts/TradeGothicLTStd.woff') format('woff'), url('fonts/TradeGothicLTStd.ttf') format('truetype');
}
@font-face {
font-family: 'TradeGothicLTStdBold';
src: url('fonts/TradeGothicLTStd-Bold.eot');
src: local('fonts/Trade Gothic LT Std'), local('fonts/TradeGothicLTStd-Bold'), url('fonts/TradeGothicLTStd-Bold.woff') format('woff'), url('fonts/TradeGothicLTStd-Bold.ttf') format('truetype');
}
#myslides h1{
font:normal 500 4.5em 'TradeGothicLTStdBold';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:2% 0 0 2%;
}
#myslides h2{
font:normal 500 3.5em 'TradeGothicLTStdRegular';
color:#d8d8d8;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:1% 2%;
clear:left;
}
#myslides p{
font:normal 500 2.5em 'TradeGothicLTStdRegular';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:1% 2%;
clear:left;
width:90%;
}
#myslides p.url{
font:normal 500 1.5em 'TradeGothicLTStdRegular';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
display:block;
position:absolute;
bottom:6%;
right:2%;
/*-- float:right;
margin:2% 2% 1% 2%;
clear:left; --*/
width:90%;
text-align:right;
}
#myslides p.url a, p.url a:visited{
font:normal 500 1em 'TradeGothicLTStdRegular';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
display:inline;
margin:1% 2%;
width:90%;
text-decoration:none;
}
#myslides p.url a:hover{
text-decoration:underline;
}
#myslides p.url img{
width:10%;
margin:0;
vertical-align: bottom;
}
img.Left, img.left{
box-shadow:0px 0px 12px rgba(0,0,0,.5);
-moz-box-shadow:0px 0px 12px rgba(0,0,0,.5);
-webkit-box-shadow:0px 0px 12px rgba(0,0,0,.5);
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
float:left;
display:inline;
margin:1%;
text-decoration:none;
outline:none;
width:30%;
max-height: 50%;
}
img.Right, img.right{
box-shadow:0px 0px 12px rgba(0,0,0,.5);
-moz-box-shadow:0px 0px 12px rgba(0,0,0,.5);
-webkit-box-shadow:0px 0px 12px rgba(0,0,0,.5);
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
float:right;
display:inline;
margin:1%;
text-decoration:none;
outline:none;
width:30%;
max-height:50%;
}
Now, some styles that are specific to main post. Including the background color of the sllides.
div#myslides{
height:100%;
width:100%;
position:relative;
overflow:hidden;
clear:both;
}
div#myslides div{
height:100%;
width:100%;
float:left;
display:block;
clear:both;
position:relative;
}
div#myslides div.container{
max-height:85%;
width:100%;
position:absolute;
top:0;
left:0;
background:transparent;
}
div#myslides div.Brown{
background:url(background/brown.jpg) 0 0 repeat-x;
}
div#myslides div.Darkblue, div#myslides div.DarkBlue{
background:url(background/darkblue.jpg) 0 0 repeat-x;
}
div#myslides div.Green{
background:url(background/green.jpg) 0 0 repeat-x;
}
div#myslides div.Lightblue{
background:url(background/lightblue.jpg) 0 0 repeat-x;
}
div#myslides div.Orange{
background:url(background/orange.jpg) 0 0 repeat-x;
}
div#myslides div.Purple{
background:url(background/purple.jpg) 0 0 repeat-x;
}
div#myslides div.Red{
background:url(background/red.jpg) 0 0 repeat-x;
}
Next up, the dock.
#dock{
position:absolute;
z-index:99;
bottom:0;
left:0;
height:20%;
width:100%;
background:-webkit-gradient(linear, left top, left bottom, from(rgba(137,137,137,0.8)), to(rgba(54,54,54,0.8)), color-stop(.3,#333333));
background: -moz-linear-gradient(bottom, rgba(137,137,137,0.8), rgba(54,54,54,0.8));
box-shadow:-2px 0px 12px rgba(0,0,0,.6);
-moz-box-shadow:-2px 0px 12px rgba(0,0,0,.6);
-webkit-box-shadow:-2px 0px 12px rgba(0,0,0,.6);
border-top-left-radius:18px;
-moz-border-radius-topleft:18px;
-webkit-border-top-left-radius:18px;
border-top-right-radius:18px;
-moz-border-radius-topright:18px;
-webkit-border-top-right-radius:18px;
}
#dock div{
float:left;
display:inline;
border-right:dotted .11em #fff;
height:95%;
margin:5px 1% 0 0;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
padding:0 1%;
overflow:hidden;
}
#dock div.dockleft{
padding-left:2%;
width:8%;
height:100%;
}
#dock div.dockcenter{
width:26%;
height:100%;
}
#dock div.dockright{
width:26%;
height:100%;
}
#dock div.dockfarright{
width:26%;
border-right:none;
height:100%;
}
#dock div div{
width:100%;
border:none;
height:100%;
margin:0;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
padding:0 1%;
}
#dock img{
padding:1%;
}
#dock h3, #pagesidebar h3{
font:normal 500 2.2em 'TradeGothicLTStdBold';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:0 0 5px 0;
line-height:1em;
}
#dock span.temp, #pagesidebar span.temp{
font:normal 500 200% 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:inline;
margin:1% 2%;
}
h3 span.addy{
clear:none;
font:normal 500 40% 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
display:inline;
float:right;
margin:1.3em 0 0 4em;
}
#dock ul, #pagesidebar ul{
list-style:none;
width:100%;
float:left;
display:block;
font:normal 500 1.6em 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
}
#dock ul li, #pagesidebar ul li{
margin:0 0 .1em 0;
padding-bottom:10px;
}
#dock a, #dock a:visited, #pagesidebar a, #pagesidebar a:visited{
text-decoration:none;
}
#dock a:hover, #pagesidebar a:hover{
text-decoration:underline;
}
#dock .youarehere, #dock a.youarehere:visited{
font:normal 500 1.7em 'TradeGothicLTStdLight';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
text-decoration:none;
display:inline;
position:absolute;
top:-33%;
left:2%;
background:transparent;
width:33%;
}
#dock a.youarehere:hover{
color:#1A1A1A;
text-shadow:0px 1px 1px #f4f4f4;
text-decoration:none;
background:#f4f4f4;
}
img.ted{
background:transparent;
text-decoration:none;
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
height:24%;
display:inline;
position:relative;
}
span.time, span.date{
font:normal 500 175% 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:inline;
margin:0;
clear:left;
}
span.time{
border-top:dotted 1px #fff;
}
Some styles for the ICS Calendar widget.
.scroll ul, .scroll2 ul, .scroll3 ul, .scroll ul li, .scroll2 ul li{
height:100%;
}
.scroll3 ul li, .scroll2 ul li{
height:40%;
}
ul#ics-calendar-widget{
width:100%;
list-style:none;
}
ul#ics-calendar-widget li.item{
font-family:'TradeGothicLTStdRegular';
}
ul#ics-calendar-widget li.item a{
font-family:'TradeGothicLTStdBold';
}
div.scroll ul li:first-line{
font-family:'TradeGothicLTStdBold';
}
span.tiny{
font:oblique 500 12px arial;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
}
div.scroll3 ul li a, div.scroll2 ul li a, div.scroll ul li a{
font:500 1.2em 'TradeGothicLTStdBold';
}
#dock div.scroll3 ul li{
padding-bottom:5px;
}
Finally, making the time & weather look right.
#pagesidebar{
width:100%;
height:100%;
background:transparent;
display:block;
position:absolute;
top:0;
left:0;
border:none;
}
iframe{
background:transparent;
border:none;
}
That leaves us here for the stylesheet.
/*----------Architecture----------*/
html{
height:100%;
margin:0;
padding:0;
width:100%;
background:transparent;
}
* {
margin:0;
padding:0;
}
a:link, a:visited, a:hover, a:active{
outline:none;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
}
body{
padding:0;
height:100%;
width:100%;
background:transparent;
text-align:left;
overflow:hidden;
cursor: url(images/blank.png), default;
}
/*----------CONTENT----------*/
@font-face {
font-family: 'TradeGothicLTStdLight';
src: url('fonts/TradeGothicLTStd-Light.eot');
src: local('fonts/Trade Gothic LT Std'), local('fonts/TradeGothicLTStd-Light'), url('fonts/TradeGothicLTStd-Light.woff') format('woff'), url('fonts/TradeGothicLTStd-Light.ttf') format('truetype');
}
@font-face {
font-family: 'TradeGothicLTStdRegular';
src: url('fonts/TradeGothicLTStd.eot');
src: local('fonts/Trade Gothic LT Std'), local('fonts/TradeGothicLTStd'), url('fonts/TradeGothicLTStd.woff') format('woff'), url('fonts/TradeGothicLTStd.ttf') format('truetype');
}
@font-face {
font-family: 'TradeGothicLTStdBold';
src: url('fonts/TradeGothicLTStd-Bold.eot');
src: local('fonts/Trade Gothic LT Std'), local('fonts/TradeGothicLTStd-Bold'), url('fonts/TradeGothicLTStd-Bold.woff') format('woff'), url('fonts/TradeGothicLTStd-Bold.ttf') format('truetype');
}
#myslides h1{
font:normal 500 4.5em 'TradeGothicLTStdBold';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:2% 0 0 2%;
}
#myslides h2{
font:normal 500 3.5em 'TradeGothicLTStdRegular';
color:#d8d8d8;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:1% 2%;
clear:left;
}
#myslides p{
font:normal 500 2.5em 'TradeGothicLTStdRegular';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:1% 2%;
clear:left;
width:90%;
}
#myslides p.url{
font:normal 500 1.5em 'TradeGothicLTStdRegular';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
display:block;
position:absolute;
bottom:6%;
right:2%;
/*-- float:right;
margin:2% 2% 1% 2%;
clear:left; --*/
width:90%;
text-align:right;
}
#myslides p.url a, p.url a:visited{
font:normal 500 1em 'TradeGothicLTStdRegular';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
display:inline;
margin:1% 2%;
width:90%;
text-decoration:none;
}
#myslides p.url a:hover{
text-decoration:underline;
}
#myslides p.url img{
width:10%;
margin:0;
vertical-align: bottom;
}
img.Left, img.left{
box-shadow:0px 0px 12px rgba(0,0,0,.5);
-moz-box-shadow:0px 0px 12px rgba(0,0,0,.5);
-webkit-box-shadow:0px 0px 12px rgba(0,0,0,.5);
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
float:left;
display:inline;
margin:1%;
text-decoration:none;
outline:none;
width:30%;
max-height: 50%;
}
img.Right, img.right{
box-shadow:0px 0px 12px rgba(0,0,0,.5);
-moz-box-shadow:0px 0px 12px rgba(0,0,0,.5);
-webkit-box-shadow:0px 0px 12px rgba(0,0,0,.5);
border-radius:7px;
-moz-border-radius:7px;
-webkit-border-radius:7px;
float:right;
display:inline;
margin:1%;
text-decoration:none;
outline:none;
width:30%;
max-height:50%;
}
/*----------SLIDER----------*/
div#myslides{
height:100%;
width:100%;
position:relative;
overflow:hidden;
clear:both;
}
div#myslides div{
height:100%;
width:100%;
float:left;
display:block;
clear:both;
position:relative;
}
div#myslides div.container{
max-height:85%;
width:100%;
position:absolute;
top:0;
left:0;
background:transparent;
}
div#myslides div.Brown{
background:url(background/brown.jpg) 0 0 repeat-x;
}
div#myslides div.Darkblue, div#myslides div.DarkBlue{
background:url(background/darkblue.jpg) 0 0 repeat-x;
}
div#myslides div.Green{
background:url(background/green.jpg) 0 0 repeat-x;
}
div#myslides div.Lightblue{
background:url(background/lightblue.jpg) 0 0 repeat-x;
}
div#myslides div.Orange{
background:url(background/orange.jpg) 0 0 repeat-x;
}
div#myslides div.Purple{
background:url(background/purple.jpg) 0 0 repeat-x;
}
div#myslides div.Red{
background:url(background/red.jpg) 0 0 repeat-x;
}
/*----------DOCK----------*/
#dock{
position:absolute;
z-index:99;
bottom:0;
left:0;
height:20%;
width:100%;
background:-webkit-gradient(linear, left top, left bottom, from(rgba(137,137,137,0.8)), to(rgba(54,54,54,0.8)), color-stop(.3,#333333));
background: -moz-linear-gradient(bottom, rgba(137,137,137,0.8), rgba(54,54,54,0.8));
box-shadow:-2px 0px 12px rgba(0,0,0,.6);
-moz-box-shadow:-2px 0px 12px rgba(0,0,0,.6);
-webkit-box-shadow:-2px 0px 12px rgba(0,0,0,.6);
border-top-left-radius:18px;
-moz-border-radius-topleft:18px;
-webkit-border-top-left-radius:18px;
border-top-right-radius:18px;
-moz-border-radius-topright:18px;
-webkit-border-top-right-radius:18px;
}
#dock div{
float:left;
display:inline;
border-right:dotted .11em #fff;
height:95%;
margin:5px 1% 0 0;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
padding:0 1%;
overflow:hidden;
}
#dock div.dockleft{
padding-left:2%;
width:8%;
height:100%;
}
#dock div.dockcenter{
width:26%;
height:100%;
}
#dock div.dockright{
width:26%;
height:100%;
}
#dock div.dockfarright{
width:26%;
border-right:none;
height:100%;
}
#dock div div{
width:100%;
border:none;
height:100%;
margin:0;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
padding:0 1%;
}
#dock img{
padding:1%;
}
#dock h3, #pagesidebar h3{
font:normal 500 2.2em 'TradeGothicLTStdBold';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:block;
margin:0 0 5px 0;
line-height:1em;
}
#dock span.temp, #pagesidebar span.temp{
font:normal 500 200% 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:inline;
margin:1% 2%;
}
h3 span.addy{
clear:none;
font:normal 500 40% 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
display:inline;
float:right;
margin:1.3em 0 0 4em;
}
#dock ul, #pagesidebar ul{
list-style:none;
width:100%;
float:left;
display:block;
font:normal 500 1.6em 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
}
#dock ul li, #pagesidebar ul li{
margin:0 0 .1em 0;
padding-bottom:10px;
}
#dock a, #dock a:visited, #pagesidebar a, #pagesidebar a:visited{
text-decoration:none;
}
#dock a:hover, #pagesidebar a:hover{
text-decoration:underline;
}
#dock .youarehere, #dock a.youarehere:visited{
font:normal 500 1.7em 'TradeGothicLTStdLight';
color:#ccc;
text-shadow:0px 1px 1px #2b2b2b;
text-decoration:none;
display:inline;
position:absolute;
top:-33%;
left:2%;
background:transparent;
width:33%;
}
#dock a.youarehere:hover{
color:#1A1A1A;
text-shadow:0px 1px 1px #f4f4f4;
text-decoration:none;
background:#f4f4f4;
}
span.time, span.date{
font:normal 500 175% 'TradeGothicLTStdRegular';
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
float:left;
display:inline;
margin:0;
clear:left;
}
span.time{
border-top:dotted 1px #fff;
}
/*----------GCAL----------*/
.scroll ul, .scroll2 ul, .scroll3 ul, .scroll ul li, .scroll2 ul li{
height:100%;
}
.scroll3 ul li, .scroll2 ul li{
height:40%;
}
ul#ics-calendar-widget{
width:100%;
list-style:none;
}
ul#ics-calendar-widget li.item{
font-family:'TradeGothicLTStdRegular';
}
ul#ics-calendar-widget li.item a{
font-family:'TradeGothicLTStdBold';
}
div.scroll ul li:first-line{
font-family:'TradeGothicLTStdBold';
}
span.tiny{
font:oblique 500 12px arial;
color:#fff;
text-shadow:0px 1px 1px #2b2b2b;
}
div.scroll3 ul li a, div.scroll2 ul li a, div.scroll ul li a{
font:500 1.2em 'TradeGothicLTStdBold';
}
#dock div.scroll3 ul li{
padding-bottom:5px;
}
/*----------WEATHER/TIME----------*/
#pagesidebar{
width:100%;
height:100%;
background:transparent;
display:block;
position:absolute;
top:0;
left:0;
border:none;
}
iframe{
background:transparent;
border:none;
}
Security
Also, because I’m paranoid, I installed these security plugins and have a 50-character password safely generated by 1Password
- Audit Trail
- Invisible Defender
- Login LockDown
- Secure WordPress
- WP Security Scan
- WordPress Database Backup
posted by @natejones
Tagged: cheap digital signage, digital sign, digital signage, DIY digital signage, flatscreen, free digital signage, sign, signage, wordpress, wp






Looks very nice! I want to make something similar. I’m not really familiar with WordPress, though. Could you please help me out here? Which files do I need to edit? Many thanks.
Hey, im looking for a signage with wordpress and your idea looks nice but it doesn’t work on my blog. I can’t find out what’s wrong – maybe you build a package with the Plugins and a Theme ? I don’t know where i have put the *.js Files, the style looks different too and the time widget dont work
thank you for your work
First of all thank you! Using the information above, I created a Digital Signage website, very happy with the result.
There are two errors in the information above;
First, you are linking to QR Code Widget instead of the QR Code Tag Plugin. Secondly, the Cool Weather Plugin is not really necessary, so there is no need to download and use it because you need the Weather.com Plugin (wp-weather) and not the Cool Weather Plugin (or else the weather (dock) section won’t work).
Last, I had trouble getting the weather dock working (, and after many tries I got but I think you should ellobrate the House of Mirrors
- from The Netherlands
Oli – I’m going to have to put this on GitHub; I’ll post when it’s up.
Thanks for the update, ENIX. I’m glad it’s working for you. Also, thanks for the clarification on the post; I’ll update those details.
@natejones, glad to be of help, and of all the free/paid digital signage software I have tried, this works the best, because of wordpress it is very customizable and user friendly
I am trying to do (customize it) more, for example the idea was to add a video file in the post (locally or on youtube for example) and show it fullscreen (with the dock shown below); I am at the point achieving this by a simple if statement that checks if a custom field has been selected, so the possibilities are endless. I can share my customizations if anybody is interested.
Again thank you for this!
Theme’s now on Github for your forking pleasure. Please make it better. https://github.com/natejones/DigitalSignageWordpress
Nate,
Thanks for sharing your process for implementing a digital signage system using WordPress. I’m using your documentation and code as a basis for a solution here at my school.
I’m happy to help. It could be much improved; please feel free to help contribute on GitHub. Come back with a link or picture of your end product. I’d love to see it.
Nate,
I actually got rid of several docks in the bottom since we didn’t want all of them. But I was successful in writing JavaScript to create the date/time refresh for the left dock that doesn’t require any iframe/house of mirrors. The downside is that I don’t allow that dock to modified. Do you think the left dock modifications I made would be useful to contribute back? Or will folks prefer the flexibility of putting what they want in that location?
Jack,
Frankly, the current time iframe nonsense is the most embarrassing and inelegant part of the entire thing and i’d love to incorporate a cleaner option. If you’re on Git, I’d welcome a fork and happily consider committing it back into the trunk. I’m hoping to rewrite the entire theme to make it work much better.