Thème WordPress JQuery Mobile from Scratch

Il est devenu indispensable de proposer des versions mobiles de nos sites internet. Avec WordPress, la mise en place d’une version dédiée aux smartphones est d’une simplicité étonnante. De nombreux plugins proposent en effet de rediriger automatiquement nos visiteurs vers une version mobile de notre blog.
La première question qui nous vient à l’esprit est la suivante : faut-il pour créer un sous-domaine du type http://m.monsite.com ou simplement proposer un affichage différent pour une même url ? La création d’un sous-domaine et d’une version spécifique peut nous amener à penser qu’il est nécessaire d’installer un deuxième wordpress pour un même blog (ou un wordpress en multisite) avec tout ce que cela engendre : duplication du contenu, synchronisation entre les deux blogs, va-t-on générer du duplicate content aux yeux de google, …
Avant de lancer les grands travaux, un petit tour sur le googlewebmastercentral pour lire les conseils de google pour le référencement mobile permet de couper court à cette réflexion. Google explique qu’il est tout à fait possible d’utiliser une même url pour une version desktop et une version mobile à condition de bien gérer le user-agent afin de guider correctement ses crawlers que sont Googlebot pour les versions bureaux et Googlebot-Mobile pour les versions mobiles.

If you serve all types of content from www.example.com, i.e. serving desktop-optimized content or mobile-optimized content from the same URL depending on the User-agent, this will also lead to correct crawling by Googlebot and Googlebot-Mobile. This is not considered cloaking by Google.

http://googlewebmastercentral.blogspot.fr/2011/02/making-websites-mobile-friendly.html

Pour un simple blog wordpress, il est donc très intéressant dans un soucis de productivité d’utiliser les mêmes url pour les deux versions. De nombreux plugins gratuits permettent d’effectuer cette redirection.

Pour mettre en place la version mobile du site, mon choix se porte sur WordPress Mobile Pack. Ce plugin, qui répond aux attentes de google, permet notamment de choisir le thème de sa version mobile, thème qui sera réalisé à l’aide du framework JQuery Mobile. Pourquoi JQuery mobile ? Le framework est compatible avec quasiment tout ce qui fait sur le marché du smartphone, dispose d’une importante communauté, d’une documentation complète et de mises à jour régulières. La configuration du plugin est très simple, je ne vais pas me pencher dessus ici.

les différents templates de notre thème

Je vais reprendre l’architecture classique d’un thème wordpress. Avec JQuery Mobile, il suffit simplement de donner aux différentes balises des attributs spécifiques. Je vous invite à lire la documentation de jquery pour avoir des informations complètes pour chacun de ces attributs ( http://jquerymobile.com/demos/ ).

Voici le squelette d’une page type tirant profit de JQuery Mobile.

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css" />
<link rel="stylesheet" type="text/css" media="all" href="<?php bloginfo( 'stylesheet_url' ); ?>" />

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>
</head>
<body>

<div data-role="page">

<div data-role="header">
<h1>Page Title</h1>
</div><!-- /header -->

<div data-role="content">
<p>Page content goes here.</p>
</div><!-- /content -->

<div data-role="footer">
<h4>Page Footer</h4>
</div><!-- /footer -->
</div><!-- /page -->

</body>
</html>
Avant de vous lancer dans la lecture de ce tutoriel, vous pouvez avant observer le thème obtenu à l’adresse suivante: http://leblogsports.fr/ .

Commençons donc par le fichier header.php.

On se contente dans le head d’intégrer jquery, jquerymobile (fichiers javascript et css). Dans le body, nous utilisons data-role= »page » data-theme= »b » sur le premier div pour indiquer à jquery mobile le début de notre page et le thème choisi, b correspond au thème noir. Ensuite nous indiquons à nous donnons au header et au nav les attributs qui permettront à jmobile de les identifier data-role= »header » data-position= »fixed » et data-role= »navbar ».
La navbar est composée d’un lien vers la home et de deux ancres permettant d’ouvrir deux menus latéraux affichant respectivement les catégories du blog et la recherche. Ces deux menus sont codés dans le fichier footer.php.

<!doctype html>
<html <?php language_attributes(); ?>>
<head>

<meta charset="<?php bloginfo( 'charset' ); ?>" />
<meta name="viewport" content="width=device-width" />

<title><?php wp_title(''); ?></title>

<link rel="stylesheet" href="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.css" />
<link rel="stylesheet" type="text/css" media="all" href="<?php bloginfo( 'stylesheet_url' ); ?>" />

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://code.jquery.com/mobile/1.4.2/jquery.mobile-1.4.2.min.js"></script>

<link rel="pingback" href="<?php bloginfo( 'pingback_url' ); ?>" />
<!--[if lt IE 9]>
<script src="<?php echo get_template_directory_uri(); ?>/js/html5.js" type="text/javascript"></script>
<![endif]-->
<?php
wp_head();
if ( is_singular() && get_option( 'thread_comments' ) )
wp_enqueue_script( 'comment-reply' );
?>

</head>

<body>

<div data-role="page" data-theme="b" id="page" class="hfeed">

<header data-role="header" data-position="fixed" id="branding" role="banner">
<?php if(is_home()){?><h1 id="site-title"><?php } else { ?><h2 id="site-title"><?php } ?>
<a href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php bloginfo( 'name' ); ?>"><?php bloginfo( 'name' ); ?></a>
<?php if(is_home()){?></h1><?php } else { ?></h2><?php } ?>

    <nav data-role="navbar">
        <ul>
            <li><a data-role="button" data-icon="home" data-iconpos="left" data-inline="true" href="<?php echo esc_url( home_url( '/' ) ); ?>" title="<?php bloginfo( 'name' ); ?>"><?php bloginfo( 'name' ); ?></a></li>
            <li><a data-role="button" data-icon="bars" data-iconpos="left" data-inline="true" href="#nav-panel">Catégories</a></li>
<li><a href="#search" data-role="button" data-icon="search" data-iconpos="left">Rechercher</a>
<li><a href="#" data-role="button" data-icon="back" data-rel="back" data-iconpos="left" title="Go back">Back</a></li>
        </ul>
    </nav><!-- /navbar -->
				</header><!-- /header -->

Passons maintenant au fichier index.php. Nous indiquons à jquery mobile avec data-role= »content » pour le premier div que le contenu de ce dernier est le contenu de la page. Nous allons lister les derniers billets en utilisant listview. Il suffit simplement de donner à notre ul l’attribut data-role= »listview ».


<?php get_header(); ?>

<section id="primary">
<div data-role="content" id="content" role="main">

<div>
<?php bloginfo( 'name' ); ?>: <?php echo get_bloginfo( 'description', 'display' ); ?>
</div>

<h4>RECENT POSTS <?php if($paged>0) { ?> - page <?php echo $paged; } ?></h4>

<ul data-role="listview" data-inset="true">
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

<li><a href="<?php the_permalink(); ?>">
<?php echo attachment_image($post->ID, 'thumbnail', 'alt="' . $post->post_title . '"'); ?>
<h2><?php the_title(); ?></h2>
<p><small><?php the_time('j/m/Y ') ?></small></p>
</a></li>

<?php endwhile; ?>
</ul>

<div><?php next_posts_link(); ?></div>
<div><?php previous_posts_link(); ?></div>

<?php else : ?>

<article id="post-0">
<header class="entry-header">
<h1 class="entry-title">Nothing Found</h1>
</header><!-- .entry-header -->

<div class="entry-content">
<p>Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.</p>
<?php get_search_form(); ?>
</div><!-- .entry-content -->
</article><!-- #post-0 -->

<?php endif; ?>

</div><!-- #content -->
</section>

<?php get_footer(); ?>

Passons maintenant au fichier footer.php où sont présents deux panels s’ouvrant sur la gauche et la droite et affichant les catégories et un formulaire de recherche.

<!-- Start of : #categories -->
<div data-role="panel" data-position="left" data-position-fixed="false" data-display="overlay" id="nav-panel" data-theme="b">
		<ul data-role="listview" data-theme="b" data-divider-theme="b" class="nav-search">
<li data-icon="delete">
							<a href="#" data-rel="close">Fermer le menu</a>
						</li>
			<?php wp_list_categories('title_li='); ?>
		</ul>
</div><!-- categories -->

<!-- Start of : #search -->
<div data-role="panel" data-position="right" data-position-fixed="false" data-display="overlay" id="search" data-theme="b">
<?php include("searchform.php"); ?>
<a href="#" data-rel="close" class="ui-btn ui-corner-all ui-shadow ui-mini ui-btn-inline ui-icon-delete ui-btn-icon-right">Fermer</a>
						</li>
</div><!-- /search -->

</div><!-- /page -->

<?php wp_footer(); ?>

</body>
</html>

Passons au fichier archive.php, utiliser pour afficher les catégories et les tags. Rien de nouveau, ce fichier est quasi-identique au fichier index.php.


<?php get_header(); ?>

<section id="primary">
<div id="content" role="main">

<?php if ( have_posts() ) : ?>

<header class="page-header">
<h1 class="page-title">
<?php if ( is_day() ) : ?>
<?php printf( __( 'Daily Archives: %s', 'twentyeleven' ), '<span>' . get_the_date() . '</span>' ); ?>
<?php elseif ( is_month() ) : ?>
<?php printf( __( 'Monthly Archives: %s', 'twentyeleven' ), '<span>' . get_the_date( _x( 'F Y', 'monthly archives date format', 'twentyeleven' ) ) . '</span>' ); ?>
<?php elseif ( is_year() ) : ?>
<?php printf( __( 'Yearly Archives: %s', 'twentyeleven' ), '<span>' . get_the_date( _x( 'Y', 'yearly archives date format', 'twentyeleven' ) ) . '</span>' ); ?>
<?php else : ?>
<?php _e( 'Blog Archives', 'twentyeleven' ); ?>
<?php endif; ?>
</h1>
</header>

<?php if(category_description()!=""){
echo "<div>".category_description()."</div>";
} ?>

<ul data-role="listview" data-inset="true">
<?php while ( have_posts() ) : the_post(); ?>

<li><a href="<?php the_permalink(); ?>">
<?php echo attachment_image($post->ID, 'thumbnail', 'alt="' . $post->post_title . '"'); ?>
<h2><?php the_title(); ?></h2>
<p><small><?php the_time('j/m/Y ') ?></small></p>
</a></li>

<?php endwhile; ?>
</ul>

<div><?php next_posts_link(); ?></div>
<div><?php previous_posts_link(); ?></div>

<?php else : ?>

<article id="post-0" class="post no-results not-found">
<header class="entry-header">
<h1 class="entry-title"><?php _e( 'Nothing Found', 'twentyeleven' ); ?></h1>
</header><!-- .entry-header -->

<div class="entry-content">
<p><?php _e( 'Apologies, but no results were found for the requested archive. Perhaps searching will help find a related post.', 'twentyeleven' ); ?></p>
<?php get_search_form(); ?>
</div><!-- .entry-content -->
</article><!-- #post-0 -->

<?php endif; ?>

</div><!-- #content -->
</section><!-- #primary -->

<?php get_footer(); ?>

Passons maintenant au fichier single.php, qui permet d’afficher les billets.

<?php get_header(); ?>

<section id="primary">
<div data-role="content" id="content" role="main">

<?php while ( have_posts() ) : the_post(); ?>

<article id="post-<?php the_ID(); ?>" class="hentry">
<header class="entry-header">
<h1 class="entry-title"><?php the_title(); ?></h1>

<footer class="entry-meta">
<abbr class="published" title="<?php the_date("YMDTh:m:s+Z"); ?>"><?php the_date ("Y/m/d"); ?></abbr> by <?php the_author(); ?>
</footer><!-- .entry-meta -->

</header><!-- .entry-header -->

<div class="entry-content">
<?php the_content(); ?>

<h3>Share</h3>
<a data-role="button" data-icon="star" data-iconpos="left" data-inline="true" target="_blank" title="Twitter" href="https://twitter.com/share?url=<?php the_permalink(); ?>&text=<?php the_title(); ?>&via=jeuxfr" rel="nofollow" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=400,width=700');return false;">Twitter</a>

<a data-role="button" data-icon="star" data-iconpos="left" data-inline="true" target="_blank" title="Facebook" href="https://www.facebook.com/sharer.php?u=<?php the_permalink(); ?>&t=<?php the_title(); ?>" rel="nofollow" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=500,width=700');return false;">Facebook</a>

<a data-role="button" data-icon="star" data-iconpos="left" data-inline="true" target="_blank" title="Google +" href="https://plus.google.com/share?url=<?php the_permalink(); ?>&hl=fr" rel="nofollow" onclick="javascript:window.open(this.href, '', 'menubar=no,toolbar=no,resizable=yes,scrollbars=yes,height=450,width=650');return false;">Google+</a>

</div><!-- .entry-content -->

<footer class="entry-meta">
<h3>Posted in:</h3>

<?php
$categories = get_the_category($post->ID);
foreach($categories as $category) { ?>
<a href="<?php echo get_category_link($category->term_id ); ?>" data-role="button" data-icon="grid" data-iconpos="left" data-inline="true"><?php echo $category->cat_name; ?></a>
<?php }
$posttags = get_the_tags();
if ($posttags) {
foreach($posttags as $tag) { ?>
<a href="<?php echo get_tag_link($tag->term_id); ?>" data-role="button" data-icon="grid" data-iconpos="left" data-inline="true"><?php echo $tag->name; ?></a>
<?php }
} ?>
</footer><!-- .entry-meta -->

</article><!-- #post-<?php the_ID(); ?> -->

<?php endwhile; ?>

</div><!-- #content -->
</section><!-- #primary -->

<aside>

<h3 class="gris">Recent Posts</h3>
<ul data-role="listview" data-inset="true">
<?php
$args = array( 'numberposts' => '5', 'post_type' => 'post', 'post_status' => 'publish' );
$recent_posts = wp_get_recent_posts( $args );
foreach( $recent_posts as $recent ){
echo '<li><a href="' . get_permalink($recent["ID"]) . '" title="'.esc_attr($recent["post_title"]).'" >' . $recent["post_title"].'</a> </li> ';
} ?>
</ul>

</aside><!-- aside -->

<?php get_footer(); ?>

Passons au fichier searchform.php.

<form method="get" id="searchform" action="<?php print get_option('home'); ?>/">
<div>
<input type="search" value="<?php echo wp_specialchars($s, 1); ?>" name="s" id="s" placeholder="Search" results="0" />
<input class='button' type="submit" id="searchsubmit" value="<?php _e('Search', 'wpmp'); ?>" />
</div>
</form>

Et au fichier search.php, permettant d’afficher les résultats.

<?php get_header(); ?>

<section id="primary">
<div data-role="content" id="content" role="main">

<?php if ( have_posts() ) : ?>

<header class="page-header">
<h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'twentyeleven' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
</header>

<ul data-role="listview" data-inset="true">
<?php if (have_posts()) : while (have_posts()) : the_post(); ?>

<li><a href="<?php the_permalink(); ?>">
<?php echo attachment_image($post->ID, 'thumbnail', 'alt="' . $post->post_title . '"'); ?>
<h2><?php the_title(); ?></h2>
<p><small><?php the_time('j/m/Y ') ?></small></p>
</a></li>

<?php endwhile; ?>
</ul>

<div><?php next_posts_link(); ?></div>
<div><?php previous_posts_link(); ?></div>

<?php else : ?>

<article id="post-0" class="post no-results not-found">
<header class="entry-header">
<h1 class="entry-title">Nothing Found</h1>
</header><!-- .entry-header -->

<div class="entry-content">
<p>Sorry, but nothing matched your search criteria. Please try again with some different keywords.</p>
<?php get_search_form(); ?>
</div><!-- .entry-content -->
</article><!-- #post-0 -->

<?php endif; ?>

</div><!-- #content -->
</section><!-- #primary -->

<?php get_footer(); ?>

Passons au fichier comments.php.

<?php if ( post_password_required() ) { return; } ?>

<section id="comments" class="themeform">

<?php if ( have_comments() ) : global $wp_query; ?>

<h3 class="heading"><?php comments_number( ('No Responses'), ('1 Response'), ('% Responses') ); ?></h3>

<ul class="comment-tabs group">
<li class="active"><a href="#commentlist-container"><i class="fa fa-comments-o"></i><?php _e( 'Comments'); ?><span><?php echo count($wp_query->comments_by_type['comment']); ?></span></a></li>
<li><a href="#pinglist-container"><i class="fa fa-share"></i><?php _e( 'Pingbacks'); ?><span><?php echo count($wp_query->comments_by_type['pings']); ?></span></a></li>
</ul>

<?php if ( ! empty( $comments_by_type['comment'] ) ) { ?>
<div id="commentlist-container" class="comment-tab">

<ol class="commentlist">
<?php wp_list_comments( 'avatar_size=96&type=comment' ); ?>
</ol><!--/.commentlist-->

<?php if ( get_comment_pages_count() && get_option('page_comments') ) : ?>
<nav class="comments-nav group">
<div class="nav-previous"><?php previous_comments_link(); ?></div>
<div class="nav-next"><?php next_comments_link(); ?></div>
</nav><!--/.comments-nav-->
<?php endif; ?>

</div>
<?php } ?>

<?php if ( ! empty( $comments_by_type['pings'] ) ) { ?>
<div id="pinglist-container" class="comment-tab">

<ol class="pinglist">
<?php // not calling wp_list_comments twice, as it breaks pagination
$pings = $comments_by_type['pings'];
foreach ($pings as $ping) { ?>
<li class="ping">
<div class="ping-link"><?php comment_author_link($ping); ?></div>
<div class="ping-meta"><?php comment_date( get_option( 'date_format' ), $ping ); ?></div>
<div class="ping-content"><?php comment_text($ping); ?></div>
</li>
<?php } ?>
</ol><!--/.pinglist-->

</div>
<?php } ?>

<?php else: // if there are no comments yet ?>

<?php if (comments_open()) : ?>
<!-- comments open, no comments -->
<?php else : ?>
<!-- comments closed, no comments -->
<?php endif; ?>

<?php endif; ?>

<?php if ( comments_open() ) { comment_form(); } ?>

</section><!--/#comments-->

Et enfin le fichier style.css. avec quelques règles pour avoir des images et des vidéos responsive friendly.

/*
Theme Name: JQuery Mobile Theme
Theme URI: http://leblogduwebmaster.fr/theme-wordpress-jquery-mobile-from-scratch-313/
Description: A Mobile Theme For WordPress With JQuery Mobile.
Version: 0.1
Author: leblogduwebmaster.fr
Author URI: leblogduwebmaster.fr
*/

.alignleft{float:left;display:block;margin:10px;}
.wp-caption-text, .aligncenter, .wp-caption, iframe, object, img, video{display:block;padding:0;margin:0 auto;max-width:100%;clear:both;}

Voici le fichier functions.php, qui contient une fonction permettant de récupérer la miniature de la première image d’un billet.

function attachment_image($postid=0, $size='thumbnail', $attributes='') {
if ($postid<1) $postid = get_the_ID();
if ($images = get_children(array(
'post_parent' => $postid,
'post_type' => 'attachment',
'numberposts' => 1,
'order'=> 'ASC',
'orderby'=> 'menu_order',
'post_mime_type' => 'image',)))
foreach($images as $image) {
$attachment=wp_get_attachment_image_src($image->ID, $size);
?><img src="<?php echo $attachment[0]; ?>" <?php echo $attributes; ?> /><?php
}
}
Publié dans jQuery, Wordpress

quand j’aurai le temps

  • les filtres wordpress
  • plugin wordpress et enregistrement de données
  • les wordpress custom post type
  • la bdd d'un blog wordpress
  • la balise more de wp
  • personnaliser une galerie wp
  • gérer les longueurs des extraits de wp
  • les animations css3
  • le memento symphony2
  • le squelette d'une page html5
  • liste sur plusieurs colonnes
  • le responsive design
  • exemple d'un jeu basique en html5
  • la réplication des bases de données
  • mettre en place une architecture en silo avec wp
  • parser un fichier xml (donc un rss) avec php5
  • mettre en place lightbox sans plugin
  • améliorer les performances de son wp
  • ajouter un bouton à l'éditeur de texte de wp
  • ...