Implementació a Wordpress d'un menú d'opcions amb desplaçament automàtic segons la posició del ratolí

Introducció

Aquest tutorial explica com fer un menú semblant o equiparable a aquest dins de Wordpress, i es basa en la documentació proveïda al mateix lloc web però també necessàriament en moltes altres pàgines visitades.

Malgrat la obvietat, pot estalviar algun maldecap fer saber que aquesta solució és útil quan l'espai que el conjunt de les opcions del menú ocupa és més gran que la grandària del menú definida dins el CSS. Si les opcions ocupen menys que el total del menú, òbviament no hi ha cap necessitat de desplaçar res, i la solució proposada no ho farà.

Al llarg de la implementació d'aquest menú a la pàgina d'un dels meus clients, em vaig trobar amb problemes principalment a causa del fet que a la mateixa pàgina ja hi havia un altre element que, com aquest menú, feia ús de llibreries extra de javascript, en aquest cas jQuery, i això semblava causar unes obscures incompatibilitats que, evidentment, em va caldre resoldre.

Bé, de fet em vaig trobar amb problemes molt abans, perquè pel camí he provat moltes altres opcions de desplaçament que m'han donat problemes similars, però al final he optat per aquesta.

Per què aquesta opció?
  • Perquè em va semblar la més senzilla de fer funcionar. És a dir, aquella en què entraven en joc menys variables.
  • Perquè em va semblar molt útil no haver d'obligar l'usuari a anar fent clic a les molestes sagetes (molestes quan en pots prescindir, és clar!)
  • Perquè permet utilitzar tantes instàncies d'un menú amb desplaçament (en altres paraules, tants menús) com sigui necessari de manera fàcil i lògica, i permet integrar fàcilment el CSS necessari per a l'script amb el que nosaltres vulguem definir o tinguem ja definit.
  • Perquè permet incorporar a l'estat de pas del cursor per sobre les icones/elements del menú (on mouse over) text explicatiu de la icona.

Comencem

La primera qüestió que cal tenir resolta és on anirà ubicat aquest menú. Això no s'aborda en aquest tutorial i és quelcom que hauràs resolt posicionant amb CSS. En el meu cas, el codi que necessitava per fer funcionar l'script i pel que fa a les etiquetes XHTML, dins els altres div posicionats oportunament, tenia aquest aspecte:

  <div class="retallMenuSupEsquerre">
  	<ul class="retallMenuSupEsquerre">
  		<li>
  			<a href="<?php bloginfo('url') ?>/?p=42">
  				<img src="<?php bloginfo('stylesheet_directory'); ?>/images/quelcom1.jpg" />
  				<span>quelcom 1</span>
  			</a>
  		</li>
  		<li>
  			<a href="<?php bloginfo('url') ?>/?p=45">
  				<img src="<?php bloginfo('stylesheet_directory'); ?>/images/quelcom2.jpg" />
  				<span>quelcom 2</span>
  			</a>
  		</li>
  		<li>
  			<a href="<?php bloginfo('url') ?>/?p=47">
  				<img src="<?php bloginfo('stylesheet_directory'); ?>/images/quelcom3.jpg" />
  				<span>quelcom 3</span>
  			</a>
  		</li>
  	</ul>
  </div>
  • El div class=“retallMenuSupEsquerre” és el primer element imprescindible per a l'script. Després veurem que el podem modificar amb CSS, però també haurem de respectar algunes parts del CSS original
  • El segon element imprescindible és un ul que sigui de la mateixa classe que el div
  • Després tenim uns elements de llista, tants com opcions hagi de tenir el menú. No cal ser gaire llest per endevinar que aquest menú tindria 3 opcions: quelcom 1, quelcom 2 i quelcom 3.
  • Dins de cada element de llista hi ha un element d'enllaç i, dins aquest darrer, una imatge:
    • L'element d'enllaç (a) té una etiqueta bloginfo que imprimeix la url actual del Wordpress, de tal manera que podem enllaçar amb posts i pàgines amb una mena de ruta pseudo-relativa,
    • I la imatge es crida també fent ús del bloginfo i es troba dins el directori images del directori de la plantilla activa en aquell moment. Podria ser, però, qualsevol altre directori, sempre i quan la ruta estigui convenientment especificada.
Inclusió del CSS

Quan ja hem introduït els elements de l'XHTML, hem de declarar aquestes classes i especificacions en el CSS, a fi que després la funció de javascript pugui actuar d'acord amb els valors assignats. De la pàgina de la documentació extrec directament això, només canviant el nom de la classe per defecte pel nom que he utilitzat en el meu exemple:

  div.retallMenuSupEsquerre {
  	/* Set it so we could calculate the offsetLeft */
  	position: relative;
  	height: 145px;
  	width: 500px;
  	/* Add scroll-bars */
  	overflow: auto;
  	}
  	
  ul.retallMenuSupEsquerre {
  	display: block;
  	height: 110px;
  	/* Max width here, for users without Javascript */
  	width: 1500px;
  	padding: 15px 0 0 15px;
  	/* Remove default margin */
  	margin: 0;
  	background: url('navigation.png');
  	list-style: none;
  	}
  
  .retallMenuSupEsquerre li {
  	display: block;
  	float: left;
  	padding: 0 4px;
  	}
  
  .retallMenuSupEsquerre a {
  	display: block;
  	text-decoration: none;
  	}
  
  .retallMenuSupEsquerre span {
  	display: none;
  	margin-top: 3px;
  	text-align: center;
  	font-size: 12px;
  	color: #fff;
  	}
  
  .retallMenuSupEsquerre a:hover span {
  	display: block;
  	}
  
  .retallMenuSupEsquerre img {
  	border: 3px #fff solid;
  	-webkit-border-radius: 3px;
  	-moz-border-radius: 3px;
  	}
  
  .retallMenuSupEsquerre a:hover img {
  	filter:alpha(opacity=50);
  	opacity: 0.5;
  	}

Bona part d'aquests paràmetres es poden modificar al vostre gust, i fins i tot pot haver-n'hi alguns que no siguin estrictament necessaris. Conserveu, però, en el seu lloc la propietat overflow i el seu valor auto dins la definició de la classe div.retallMenuSupEsquerre, ja que el javascript ha de trobar definit aquest valor a fi de poder eliminar les barres d'scroll i desencadenar el desplaçament automàtic. Internet Explorer no executarà correctament l'script si falta aquest paràmetre, tot i que altres navegadors semblen ser més tolerants.

Tingueu present també que les propietats -webkit-border-radius i -moz-border-radius no estan incloses, diria, a la versió 2 de l'especificació de CSS. No estic segur si la propietat filter tampoc.

Inclusió de les funcions de Javascript

Com hem dit, aquest efecte és possible gràcies a les llibreries jQuery, que proporcionen un accés optimitzat a funcions i possibilitats avançades de Javascript. Aquestes llibreries, siguin solucions tipus jQuery o d'altres possibles com Prototype, s'han de referenciar. Per tant, tenim per una banda l'script que fa la màgia del moviment dins el menú, i per l'altra les llibreries que aquest script necessita per funcionar.

Tots dos elements, l'script i la referenciació a les llibreries, han d'anar inclosos dins l'element head de la pàgina, ja que aquest element comprèn tots els altres que necessiten ser carregats abans que els continguts pròpiament de la pàgina. L'element head es troba dins el fitxer header.php, per defecte, però pot ser que vosaltres l'hagueu inclòs dins una única pàgina index.php. Ja veurem, però, que la referenciació a les llibreries necessita algunes precisions i correccions, des del meu punt de vista, respecte el que es diu a la pàgina de la documentació original.

Incloure l'script és tan trivial com enganxar el codi següent dins el head i assegurant-nos que ho fem després (en l'estructura del document) de la crida

  <?php wp_head(); ?>

codi de l'script:

  <script type="text/javascript">
  <!-- inicialitzador de la funció per a l'scroll de les icones dins el menú superior esquerre -->
  jQuery(document).ready(function(){
  	//Get our elements for faster access and set overlay width
  	var div = $('div.retallMenuSupEsquerre'),
  		ul = $('ul.retallMenuSupEsquerre'),
  		ulPadding = 15;
  	
  	//Get menu width
  	var divWidth = div.width();
  
  	//Remove scrollbars	
  	div.css({overflow: 'hidden'});
  	
  	//Find last image container
  	var lastLi = ul.find('li:last-child');
  	
  	//When user move mouse over menu
  	div.mousemove(function(e){
  		//As images are loaded ul width increases,
  		//so we recalculate it each time
  		var ulWidth = lastLi[0].offsetLeft + lastLi.outerWidth() + ulPadding;	
  		var left = (e.pageX - div.offset().left) * (ulWidth-divWidth) / divWidth;
  		div.scrollLeft(left);
  	});
  });
  <!-- Final inicialitzador de la funció per a l'scroll de les icones dins el menú superior esquerre -->
  </script>
  • Si observeu les ocurrències de retallMenuSupEsquerre al cos de l'XHTML, al CSS i finalment a l'anterior script, podreu entrellucar perquè és tan fàcil implementar aquesta solució a les nostres pròpies definicions de CSS. Si volguessim afegir menús addicional amb desplaçament de les seves opcions, (per exemple, un menú de classe retallMenuSupDret) només hauríem d'afegir sengles definicions de classe dins
    • el cos de l'XHTML (el menú pròpiament)
    • el CSS (la definició gràfica del menú)
    • l'script dins el head (el codi de què ha de passar dins el menú)
  • D'aquesta manera, si per exemple tinguessim tres menús amb desplaçament utilitzant aquesta solució, tindriem
    • tres definicions, una per cada menú, dins el cos de l'XHTML
    • tres conjunts de definicions dins el CSS, un per a cada classe de cada un dels menús
    • tres scripts que especificarien què ha de passar dins el menú

Si heu repassat la documentació original observareu que es fa servir

  $(document).ready(function()

en lloc de

  jQuery(document).ready(function()

Als enllaços esmentats al principi sobre CMS podeu veure diverses pàgines i articles que aborden per què majoritàriament cal evitar fer servir $ en les crides a jQuery i utilitzar directament jQuery.

Però el problema no s'acaba aquí. Resulta que la documentació original indica que cal referenciar jQuery utilitzant el següent element de referenciació d'scripts:

  <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js" type="text/javascript"></script>

El que això revela, si mirem les tripes de la nostra instal·lació de Wordpress en el cas de la versió 2.7, és que es fa servir una versió de jQuery més moderna de la que per defecte hi ha instal·lada. D'altra banda, alguns enllaços esmentats al principi sobre CMS aborden la qüestió de quina és la manera òptima de fer aquesta referenciació a les llibreries externes (encara que no siguin jQuery) en Wordpress. I la conclusió és que, a més del fet que des del meu punt de vista no és convenient haver de dependre d'uns fitxers proporcionats per pàgines de Google, cal referenciar les llibreries no dins el document header.php o index.php sinó en un fitxer ad hoc que hi ha a la instal·lació de Wordpress: functions.php, que es troba al directori de la plantilla default de Wordpress.

L'aspecte que té la primera línia d'aquest fitxer en el meu cas és el següent:

  wp_enqueue_script('jqueryUpd', '/wp-includes/js/jquery-1.3.2.min.js');

Com veieu, aquí es fa ús de la instrucció wp_enqueue_script per tal de referenciar globalment al sistema l'ús de la llibreria jquery-1.3.2.min.js. El que he fet simplement és descarregar de la pàgina proporcionada a la documentació el fitxer .js en qüestió, i posar-lo al directori que conté totes les llibreries js de Wordpress.

jqueryUpd és un identificador arbitrari que assigno a la llibreria que vull carregar i que ve a significar quelcom per l'estil de jQuery Updated. No estic segur que es pugui ser tant arbitrari en tots els casos, però en aquest no sembla donar problemes.

Si volguessim referenciar altres llibreries, relacionades o no amb jQuery, només caldria procedir de manera anàloga i referenciar-ho a functions.php. Tingueu present que les darreres versions de Wordpress ja vénen amb força llibreries instal·lades per defecte, com Prototype i scriptaculous, però probablement calgui referenciar-les explícitament per utilitzar-les.

Podeu veure més informació sobre wp_enqueue_script i totes aquestes qüestions abordades aquí dalt als enllaços sobre CMS que he indicat abans (encara no has obert la pàgina a una altra pestanya?!)

El fet que es referencïin en un fitxer extern aquestes llibreries és el motiu pel qual els scripts han d'anar després de

  <?php wp_head(); ?>

ja que aquesta és el codi que carrega, entre altres coses, les instrucciones incloses dins de functions.php. Per tant, quan l'script es declari ja han d'haver estat declarades les referències a les llibreries. Si no fos així, l'script no les podria utilitzar.

Pot ser revelador que mireu el codi font de la pàgina amb el PHP ja executat. Veureu que l'intèrpret ha inclòs les referències dins el fitxer functions.php en elements script src=“ruta/alavostra/llibreria” al document interpretat.

Finalment

Fet això el menú hauria de funcionar. Recomano molt que observeu i estudieu el codi font de la pàgina d'exemple del menú, tant per provar-ne el funcionament abans de tirar-vos-hi de cap, com per depurar els problemes si quelcom no funciona. Des del meu punt de vista, sovint és interessant assegurar-se que les coses funcionen fora d'un entorn dinàmic (sense parts interpretades amb PHP, per tant, ni inclusions a llibreries a través d'obscurs wp_enqueue_script) abans de passar a un entorn dinàmic.

Amb una mica de sort, doncs, tot el que restarà serà barallar-se amb el CSS perquè s'ajusti a les vostres necessitats