Entradas etiquetadas con PHP
WordPress 3.x para desarrolladores: Temas y plantillas, content-image.php, content-link.php, content-quote.php y content-status.php
0CONTENT-IMAGE.PHP
Creamos el archivo content-image.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php /** * The template for displaying posts in the Image Post Format on index and archive pages * * Learn more: http://codex.wordpress.org/Post_Formats * * @package WordPress * @subpackage New_Theme */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class( 'indexed' ); ?>> <header class="entry-header"> <hgroup> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <h3 class="entry-format"><?php _e( 'Image', 'newtheme' ); ?></h3> </hgroup> <?php if ( comments_open() && ! post_password_required() ) : ?> <div class="comments-link"> <?php comments_popup_link( '<span class="leave-reply">' . __( "Reply", 'newtheme' ) . '</span>', _x( '1', 'comments number', 'newtheme' ), _x( '%', 'comments number', 'newtheme' ) ); ?> </div> <?php endif; ?> </header><!-- .entry-header --> <div class="entry-content"> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <footer class="entry-meta"> <div class="entry-meta"> <?php printf( __( '<a href="%1$s" rel="bookmark"><time class="entry-date" datetime="%2$s" pubdate>%3$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%4$s" title="%5$s" rel="author">%6$s</a></span></span>', 'newtheme' ), esc_url( get_permalink() ), get_the_date( 'c' ), get_the_date(), esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ), esc_attr( sprintf( __( 'View all posts by %s', 'newtheme' ), get_the_author() ) ), get_the_author() ); ?> </div><!-- .entry-meta --> <div class="entry-meta"> <?php /* translators: used between list items, there is a space after the comma */ $categories_list = get_the_category_list( __( ', ', 'newtheme' ) ); if ( $categories_list ): ?> <span class="cat-links"> <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'newtheme' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list ); ?> </span> <?php endif; // End if categories ?> <?php /* translators: used between list items, there is a space after the comma */ $tags_list = get_the_tag_list( '', __( ', ', 'newtheme' ) ); if ( $tags_list ): ?> <span class="tag-links"> <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'newtheme' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list ); ?> </span> <?php endif; // End if $tags_list ?> <?php if ( comments_open() ) : ?> <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'newtheme' ) . '</span>', __( '<b>1</b> Reply', 'newtheme' ), __( '<b>%</b> Replies', 'newtheme' ) ); ?></span> <?php endif; // End if comments_open() ?> </div><!-- .entry-meta --> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- #entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
Este tipo de contenido simplemente muestra una imagen y su respectivo título.
CONTENT-LINK.PHP
Creamos el archivo content-link.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php /** * The template for displaying posts in the Link Post Format on index and archive pages * * Learn more: http://codex.wordpress.org/Post_Formats * * @package WordPress * @subpackage New_Theme */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <hgroup> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <h3 class="entry-format"><?php _e( 'Link', 'newtheme' ); ?></h3> </hgroup> <?php if ( comments_open() && ! post_password_required() ) : ?> <div class="comments-link"> <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'newtheme' ) . '</span>', _x( '1', 'comments number', 'newtheme' ), _x( '%', 'comments number', 'newtheme' ) ); ?> </div> <?php endif; ?> </header><!-- .entry-header --> <?php if ( is_search() ) : // Only display Excerpts for Search ?> <div class="entry-summary"> <?php the_excerpt(); ?> </div><!-- .entry-summary --> <?php else : ?> <div class="entry-content"> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <?php endif; ?> <footer class="entry-meta"> <?php newtheme_posted_on(); ?> <?php if ( comments_open() ) : ?> <span class="sep"> | </span> <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'newtheme' ) . '</span>', __( '<b>1</b> Reply', 'newtheme' ), __( '<b>%</b> Replies', 'newtheme' ) ); ?></span> <?php endif; ?> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- #entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
Este contenido es más sencillo aún. Simplemente mostramos un link o un conjunto de estos.
CONTENT-QUOTE.PHP
Creamos el archivo content-quote.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php <?php /** * The default template for displaying content * * @package WordPress * @subpackage New_Theme */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <hgroup> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <h3 class="entry-format"><?php _e( 'Quote', 'newtheme' ); ?></h3> </hgroup> <div class="entry-meta"> <?php newtheme_posted_on(); ?> </div><!-- .entry-meta --> <?php if ( comments_open() && ! post_password_required() ) : ?> <div class="comments-link"> <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'newtheme' ) . '</span>', _x( '1', 'comments number', 'newtheme' ), _x( '%', 'comments number', 'newtheme' ) ); ?> </div> <?php endif; ?> </header><!-- .entry-header --> <?php if ( is_search() ) : // Only display Excerpts for Search ?> <div class="entry-summary"> <?php the_excerpt(); ?> </div><!-- .entry-summary --> <?php else : ?> <div class="entry-content"> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <?php endif; ?> <footer class="entry-meta"> <?php $show_sep = false; ?> <?php /* translators: used between list items, there is a space after the comma */ $categories_list = get_the_category_list( __( ', ', 'newtheme' ) ); if ( $categories_list ): ?> <span class="cat-links"> <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'newtheme' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list ); $show_sep = true; ?> </span> <?php endif; // End if categories ?> <?php /* translators: used between list items, there is a space after the comma */ $tags_list = get_the_tag_list( '', __( ', ', 'newtheme' ) ); if ( $tags_list ): if ( $show_sep ) : ?> <span class="sep"> | </span> <?php endif; // End if $show_sep ?> <span class="tag-links"> <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'newtheme' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list ); $show_sep = true; ?> </span> <?php endif; // End if $tags_list ?> <?php if ( comments_open() ) : ?> <?php if ( $show_sep ) : ?> <span class="sep"> | </span> <?php endif; // End if $show_sep ?> <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'newtheme' ) . '</span>', __( '<b>1</b> Reply', 'newtheme' ), __( '<b>%</b> Replies', 'newtheme' ) ); ?></span> <?php endif; // End if comments_open() ?> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- #entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
Más de lo mismo, lo único que cambia es que aparece un subtítulo indicando que es una cita.
CONTENT-STATUS.PHP
Creamos el archivo content-status.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php /** * The template for displaying posts in the Status Post Format on index and archive pages * * Learn more: http://codex.wordpress.org/Post_Formats * * @package WordPress * @subpackage New_Theme */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <hgroup> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <h3 class="entry-format"><?php _e( 'Status', 'newtheme' ); ?></h3> </hgroup> <?php if ( comments_open() && ! post_password_required() ) : ?> <div class="comments-link"> <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'newtheme' ) . '</span>', _x( '1', 'comments number', 'newtheme' ), _x( '%', 'comments number', 'newtheme' ) ); ?> </div> <?php endif; ?> </header><!-- .entry-header --> <?php if ( is_search() ) : // Only display Excerpts for Search ?> <div class="entry-summary"> <?php the_excerpt(); ?> </div><!-- .entry-summary --> <?php else : ?> <div class="entry-content"> <div class="avatar"><?php echo get_avatar( get_the_author_meta( 'ID' ), apply_filters( 'newtheme_status_avatar', '65' ) ); ?></div> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <?php endif; ?> <footer class="entry-meta"> <?php newtheme_posted_on(); ?> <?php if ( comments_open() ) : ?> <span class="sep"> | </span> <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'newtheme' ) . '</span>', __( '<b>1</b> Reply', 'newtheme' ), __( '<b>%</b> Replies', 'newtheme' ) ); ?></span> <?php endif; ?> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- #entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
En este caso se añade la imagen del perfil del autor o avatar para acompañar al contenido.
WordPress 3.x para desarrolladores: Temas y plantillas, content-aside.php, content-featured.php y content-gallery.php
0Durante los próximos post, incluido este, explicaré las últimas plantillas que quedan por crear de nuestro tema, después continuaré el tutorial con los plugins.
CONTENT-ASIDE.PHP
WordPress dispone de varios formatos de post que pueden ser personalizados (ver: http://codex.wordpress.org/Post_Formats), entre ellos se encuentra aside, que es parecido a una actualización de Facebook, es decir, no tiene título.
Creamos el archivo content-aside.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php /** * The template for displaying posts in the Aside Post Format on index and archive pages * * Learn more: http://codex.wordpress.org/Post_Formats * * @package WordPress * @subpackage New_Theme */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <hgroup> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <h3 class="entry-format"><?php _e( 'Aside', 'newtheme' ); ?></h3> </hgroup> <?php if ( comments_open() && ! post_password_required() ) : ?> <div class="comments-link"> <?php comments_popup_link( '<span class="leave-reply">' . __( 'Reply', 'newtheme' ) . '</span>', _x( '1', 'comments number', 'newtheme' ), _x( '%', 'comments number', 'newtheme' ) ); ?> </div> <?php endif; ?> </header><!-- .entry-header --> <?php if ( is_search() ) : // Only display Excerpts for Search ?> <div class="entry-summary"> <?php the_excerpt(); ?> </div><!-- .entry-summary --> <?php else : ?> <div class="entry-content"> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <?php endif; ?> <footer class="entry-meta"> <?php newtheme_posted_on(); ?> <?php if ( comments_open() ) : ?> <span class="sep"> | </span> <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'newtheme' ) . '</span>', __( '<b>1</b> Reply', 'newtheme' ), __( '<b>%</b> Replies', 'newtheme' ) ); ?></span> <?php endif; ?> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- #entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
Como veis, lo primero que se crea es la cabecera del post, pero en este caso, en vez de mostrar el título del post se mostrará el texto «Aside«. El resto del código es prácticamente igual al de un post normal: se muestra el contenido del post y se crea el pie de este con los metadatos y los correspondientes links, entre ellos el de editar.
CONTENT-FEATURED.PHP
Los post featured son los post destacados de los que ya hemos hablado con anterioridad. Aunque este tipo de post no aparece en la lista de formatos de post, si es una características de los post normales que se puede personalizar con su propia plantilla.
Por tanto crearemos el archivo content-featured.php y añadiremos el siguiente código:
[codesyntax lang=»php»]
<?php /** * The template for displaying content featured in the showcase.php page template * * @package WordPress * @subpackage New_Theme */ global $feature_class; ?> <article id="post-<?php the_ID(); ?>" <?php post_class( $feature_class ); ?>> <header class="entry-header"> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <div class="entry-meta"> <?php newtheme_posted_on(); ?> </div><!-- .entry-meta --> </header><!-- .entry-header --> <div class="entry-summary"> <?php the_excerpt(); ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <footer class="entry-meta"> <?php /* translators: used between list items, there is a space after the comma */ $tag_list = get_the_tag_list( '', __( ', ', 'newtheme' ) ); if ( '' != $tag_list ) { $utility_text = __( 'This entry was posted in %1$s and tagged %2$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'newtheme' ); } else { $utility_text = __( 'This entry was posted in %1$s. Bookmark the <a href="%3$s" title="Permalink to %4$s" rel="bookmark">permalink</a>.', 'newtheme' ); } printf( $utility_text, /* translators: used between list items, there is a space after the comma */ get_the_category_list( __( ', ', 'newtheme' ) ), $tag_list, esc_url( get_permalink() ), the_title_attribute( 'echo=0' ) ); ?> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- .entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
Lo mismo de antes, se muestra el título, se muestra el contenido y se muestra el pie del post, la única diferencia sería que, en este caso también mostramos el texto «FEATURED» o «DESTACADO» en la página principal.
CONTENT-GALLERY.PHP
Este tipo de contenido nos permite mostrar galerías de imágenes, adjuntando las imágenes al post.
Creamos el archivo content-gallery.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php /** * The template for displaying posts in the Gallery Post Format on index and archive pages * * Learn more: http://codex.wordpress.org/Post_Formats * * @package WordPress * @subpackage New_Theme */ ?> <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>> <header class="entry-header"> <hgroup> <h2 class="entry-title"><a href="<?php the_permalink(); ?>" title="<?php printf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ); ?>" rel="bookmark"><?php the_title(); ?></a></h2> <h3 class="entry-format"><?php _e( 'Gallery', 'newtheme' ); ?></h3> </hgroup> <div class="entry-meta"> <?php newtheme_posted_on(); ?> </div><!-- .entry-meta --> </header><!-- .entry-header --> <?php if ( is_search() ) : // Only display Excerpts for search pages ?> <div class="entry-summary"> <?php the_excerpt(); ?> </div><!-- .entry-summary --> <?php else : ?> <div class="entry-content"> <?php if ( post_password_required() ) : ?> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php else : ?> <?php $images = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'menu_order', 'order' => 'ASC', 'numberposts' => 999 ) ); if ( $images ) : $total_images = count( $images ); $image = array_shift( $images ); $image_img_tag = wp_get_attachment_image( $image->ID, 'thumbnail' ); ?> <figure class="gallery-thumb"> <a href="<?php the_permalink(); ?>"><?php echo $image_img_tag; ?></a> </figure><!-- .gallery-thumb --> <p><em><?php printf( _n( 'This gallery contains <a %1$s>%2$s photo</a>.', 'This gallery contains <a %1$s>%2$s photos</a>.', $total_images, 'newtheme' ), 'href="' . esc_url( get_permalink() ) . '" title="' . sprintf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ) . '" rel="bookmark"', number_format_i18n( $total_images ) ); ?></em></p> <?php endif; ?> <?php the_excerpt(); ?> <?php endif; ?> <?php wp_link_pages( array( 'before' => '<div class="page-link"><span>' . __( 'Pages:', 'newtheme' ) . '</span>', 'after' => '</div>' ) ); ?> </div><!-- .entry-content --> <?php endif; ?> <footer class="entry-meta"> <?php $show_sep = false; ?> <?php /* translators: used between list items, there is a space after the comma */ $categories_list = get_the_category_list( __( ', ', 'newtheme' ) ); if ( $categories_list ): ?> <span class="cat-links"> <?php printf( __( '<span class="%1$s">Posted in</span> %2$s', 'newtheme' ), 'entry-utility-prep entry-utility-prep-cat-links', $categories_list ); $show_sep = true; ?> </span> <?php endif; // End if categories ?> <?php /* translators: used between list items, there is a space after the comma */ $tags_list = get_the_tag_list( '', __( ', ', 'newtheme' ) ); if ( $tags_list ): if ( $show_sep ) : ?> <span class="sep"> | </span> <?php endif; // End if $show_sep ?> <span class="tag-links"> <?php printf( __( '<span class="%1$s">Tagged</span> %2$s', 'newtheme' ), 'entry-utility-prep entry-utility-prep-tag-links', $tags_list ); $show_sep = true; ?> </span> <?php endif; // End if $tags_list ?> <?php if ( comments_open() ) : ?> <?php if ( $show_sep ) : ?> <span class="sep"> | </span> <?php endif; // End if $show_sep ?> <span class="comments-link"><?php comments_popup_link( '<span class="leave-reply">' . __( 'Leave a reply', 'newtheme' ) . '</span>', __( '<b>1</b> Reply', 'newtheme' ), __( '<b>%</b> Replies', 'newtheme' ) ); ?></span> <?php endif; // End if comments_open() ?> <?php edit_post_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </footer><!-- #entry-meta --> </article><!-- #post-<?php the_ID(); ?> -->
[/codesyntax]
La parte más importante de este código es el siguiente extracto:
[codesyntax lang=»php»]
<?php if ( post_password_required() ) : ?> <?php the_content( __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) ); ?> <?php else : ?> <?php $images = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'attachment', 'post_mime_type' => 'image', 'orderby' => 'menu_order', 'order' => 'ASC', 'numberposts' => 999 ) ); if ( $images ) : $total_images = count( $images ); $image = array_shift( $images ); $image_img_tag = wp_get_attachment_image( $image->ID, 'thumbnail' ); ?> <figure class="gallery-thumb"> <a href="<?php the_permalink(); ?>"><?php echo $image_img_tag; ?></a> </figure><!-- .gallery-thumb --> <p><em><?php printf( _n( 'This gallery contains <a %1$s>%2$s photo</a>.', 'This gallery contains <a %1$s>%2$s photos</a>.', $total_images, 'newtheme' ), 'href="' . esc_url( get_permalink() ) . '" title="' . sprintf( esc_attr__( 'Permalink to %s', 'newtheme' ), the_title_attribute( 'echo=0' ) ) . '" rel="bookmark"', number_format_i18n( $total_images ) ); ?></em></p> <?php endif; ?>
[/codesyntax]
Esta parte es la que calcula el número de imágenes en el post y las convierte en una galería.
WordPress 3.x para desarrolladores: Temas y plantillas, functions.php
0Como ya llevamos varias plantillas creadas con algunas llamadas a funciones del archivo functions.php, vamos a crearlo y añadir esas funciones, después continuaremos añadiendo más plantillas.
FUNCTIONS.PHP
Creamos el archivo functions.php y añadimos el siguiente código:
[codesyntax lang=»php»]
<?php /** * Set the content width based on the theme's design and stylesheet. */ if ( ! isset( $content_width ) ) $content_width = 584;
[/codesyntax]
Este código creara una variable que nos indicará el ancho que tendrá el contenido.
[codesyntax lang=»php»]
<?php /** * Tell WordPress to run newtheme_setup() when the 'after_setup_theme' hook is run. */ add_action( 'after_setup_theme', 'newtheme_setup' ); if ( ! function_exists( 'newtheme_setup' ) ): function newtheme_setup() { } endif;
[/codesyntax]
Le decimos a WordPress que ejecute newtheme_setup cuando el hook after_setup_theme esté funcionando. Creamos un condicional para comprobar que la función newtheme_setup no ha sido aun creada, y creamos la función.
Dentro de newtheme_setup añadiremos las siguientes lineas de código:
[codesyntax lang=»php»]
<?php load_theme_textdomain( 'newtheme', get_template_directory() . '/languages' );
[/codesyntax]
Esta línea cargará el archivo de idioma correspondiente.
[codesyntax lang=»php»]
<?php add_editor_style();
[/codesyntax]
Le indicamos a WordPress que cargue el editor de estilos. Para ello WordPress buscará el archivo editor-style.css dentro de la carpeta del tema, por tanto copiaremos los archivos editor-style.css y editor-style-rtl.css del tema Twenty Eleven a nuestro tema.
[codesyntax lang=»php»]
<?php require( get_template_directory() . '/inc/theme-options.php' ); require( get_template_directory() . '/inc/widgets.php' );
[/codesyntax]
Estas dos lineas cargan los archivos de las opciones del tema que se mostrarán en la administración y los widgets de los que disponga el tema.
[codesyntax lang=»php»]
<?php add_theme_support( 'automatic-feed-links' );
[/codesyntax]
Le indicamos a WordPress que los links de este tema se añadirán a un archivo rss que se creará automáticamente. Más sobre otros argumentos de esta función: http://codex.wordpress.org/Function_Reference/add_theme_support
[codesyntax lang=»php»]
<?php register_nav_menu( 'primary', __( 'Primary Menu', 'newtheme' ) );
[/codesyntax]
Registramos la barra de menú de la cabecera.
[codesyntax lang=»php»]
<?php add_theme_support( 'post-formats', array( 'aside', 'link', 'gallery', 'status', 'quote', 'image' ) );
[/codesyntax]
Añadimos soporte para varios tipos de formato de posts.
[codesyntax lang=»php»]
<?php $theme_options = newtheme_get_theme_options(); if ( 'dark' == $theme_options['color_scheme'] ) $default_background_color = '1d1d1d'; else $default_background_color = 'f1f1f1'; // Add support for custom backgrounds. add_theme_support( 'custom-background', array( // Let WordPress know what our default background color is. // This is dependent on our current color scheme. 'default-color' => $default_background_color, ) );
[/codesyntax]
Primero recuperamos las opciones del tema a través de la función newtheme_get_theme_options(), que se encuentra en el archivo inc/theme_options.php, el cual crearemos más delante.
Comprobamos que tipo de esquema de estilos se ha elegido y guardamos en la variable $default_background_color el valor correspondiente.
Le indicamos a WordPress el color de nuestro fondo de página.
[codesyntax lang=»php»]
<?php add_theme_support( 'post-thumbnails' );
[/codesyntax]
Le indicamos a WordPress que este tema utilizará imágenes destacadas o thumbnails.
[codesyntax lang=»php»]
<?php $custom_header_support = array( // The default header text color. 'default-text-color' => '000', // The height and width of our custom header. 'width' => apply_filters( 'newtheme_header_image_width', 1000 ), 'height' => apply_filters( 'newtheme_header_image_height', 288 ), // Support flexible heights. 'flex-height' => true, // Random image rotation by default. 'random-default' => true, // Callback for styling the header. 'wp-head-callback' => 'newtheme_header_style', // Callback for styling the header preview in the admin. 'admin-head-callback' => 'newtheme_admin_header_style', // Callback used to display the header preview in the admin. 'admin-preview-callback' => 'newtheme_admin_header_image', ); add_theme_support( 'custom-header', $custom_header_support );
[/codesyntax]
Creamos un array con los encabezados personalizados y se lo indicamos a WordPress.
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'get_custom_header' ) ) { // This is all for compatibility with versions of WordPress prior to 3.4. define( 'HEADER_TEXTCOLOR', $custom_header_support['default-text-color'] ); define( 'HEADER_IMAGE', '' ); define( 'HEADER_IMAGE_WIDTH', $custom_header_support['width'] ); define( 'HEADER_IMAGE_HEIGHT', $custom_header_support['height'] ); add_custom_image_header( $custom_header_support['wp-head-callback'], $custom_header_support['admin-head-callback'], $custom_header_support['admin-preview-callback'] ); add_custom_background(); }
[/codesyntax]
En el caso de que se utilizase este tema con una versión de WordPress inferior a la 3.4 creamos varias constantes, y añadimos las cabeceras personalizadas y el fondo a WordPress.
[codesyntax lang=»php»]
<?php set_post_thumbnail_size( $custom_header_support['width'], $custom_header_support['height'], true );
[/codesyntax]
Configuramos la imagen destacada definiendo un ancho y alto.
[codesyntax lang=»php»]
<?php add_image_size( 'large-feature', $custom_header_support['width'], $custom_header_support['height'], true ); // Used for featured posts if a large-feature doesn't exist. add_image_size( 'small-feature', 500, 300 );
[/codesyntax]
Añadimos la imagen a la cabecera definiendo su ancho y alto, además añadimos una imagen más pequeña para los post en el caso de que no existe imagen para la cabecera.
[codesyntax lang=»php»]
<?php register_default_headers( array( 'wheel' => array( 'url' => '%s/images/headers/wheel.jpg', 'thumbnail_url' => '%s/images/headers/wheel-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Wheel', 'newtheme' ) ), 'shore' => array( 'url' => '%s/images/headers/shore.jpg', 'thumbnail_url' => '%s/images/headers/shore-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Shore', 'newtheme' ) ), 'trolley' => array( 'url' => '%s/images/headers/trolley.jpg', 'thumbnail_url' => '%s/images/headers/trolley-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Trolley', 'newtheme' ) ), 'pine-cone' => array( 'url' => '%s/images/headers/pine-cone.jpg', 'thumbnail_url' => '%s/images/headers/pine-cone-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Pine Cone', 'newtheme' ) ), 'chessboard' => array( 'url' => '%s/images/headers/chessboard.jpg', 'thumbnail_url' => '%s/images/headers/chessboard-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Chessboard', 'newtheme' ) ), 'lanterns' => array( 'url' => '%s/images/headers/lanterns.jpg', 'thumbnail_url' => '%s/images/headers/lanterns-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Lanterns', 'newtheme' ) ), 'willow' => array( 'url' => '%s/images/headers/willow.jpg', 'thumbnail_url' => '%s/images/headers/willow-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Willow', 'newtheme' ) ), 'hanoi' => array( 'url' => '%s/images/headers/hanoi.jpg', 'thumbnail_url' => '%s/images/headers/hanoi-thumbnail.jpg', /* translators: header image description */ 'description' => __( 'Hanoi Plant', 'newtheme' ) ) ) );
[/codesyntax]
Este es el paquete de imágenes que el tema Twenty Eleven trae por defecto, nosotros haremos lo mismo. Si no lo habéis hecho ya, copiad la carpeta images del tema Twenty Eleven a nuestro tema.
El marcador %s indica que se debe sustituir por la uri del tema.
Como esta función tiene llamadas a otras funciones dentro del mismo archivo functions.php, vamos a crearlas.
En primer lugar crearemos la función newtheme_header_style():
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'newtheme_header_style' ) ) : /** * Styles the header image and text displayed on the blog */ function newtheme_header_style() { $text_color = get_header_textcolor(); // If no custom options for text are set, let's bail. if ( $text_color == HEADER_TEXTCOLOR ) return; // If we get this far, we have custom styles. Let's do this. ?> <style type="text/css"> <?php // Has the text been hidden? if ( 'blank' == $text_color ) : ?> #site-title, #site-description { position: absolute !important; clip: rect(1px 1px 1px 1px); /* IE6, IE7 */ clip: rect(1px, 1px, 1px, 1px); } <?php // If the user has set a custom color for the text use that else : ?> #site-title a, #site-description { color: #<?php echo $text_color; ?> !important; } <?php endif; ?> </style> <?php } endif; // newtheme_header_style
[/codesyntax]
Simplemente en esta función se generan los estilos para el título y la descripción que se ubican en la cabecera de la página.
Creamos el método newtheme_admin_header_style():
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'newtheme_admin_header_style' ) ) : /** * Styles the header image displayed on the Appearance > Header admin panel. * * Referenced via add_theme_support('custom-header') in newtheme_setup(). */ function newtheme_admin_header_style() { ?> <style type="text/css"> .appearance_page_custom-header #headimg { border: none; } #headimg h1, #desc { font-family: "Helvetica Neue", Arial, Helvetica, "Nimbus Sans L", sans-serif; } #headimg h1 { margin: 0; } #headimg h1 a { font-size: 32px; line-height: 36px; text-decoration: none; } #desc { font-size: 14px; line-height: 23px; padding: 0 0 3em; } <?php // If the user has set a custom color for the text use that if ( get_header_textcolor() != HEADER_TEXTCOLOR ) : ?> #site-title a, #site-description { color: #<?php echo get_header_textcolor(); ?>; } <?php endif; ?> #headimg img { max-width: 1000px; height: auto; width: 100%; } </style> <?php } endif; // newhtme_admin_header_style
[/codesyntax]
Esta función permite dar estilos a la imagen de la cabecera dentro de su apartado de opciones en la administración de WordPress, donde se podrá configurar cómo se ve la imagen.
Creamos la función newtheme_admin_header_image():
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'newtheme_admin_header_image' ) ) : /** * Custom header image markup displayed on the Appearance > Header admin panel. * * Referenced via add_theme_support('custom-header') in newtheme_setup(). */ function newtheme_admin_header_image() { ?> <div id="headimg"> <?php $color = get_header_textcolor(); $image = get_header_image(); if ( $color && $color != 'blank' ) $style = ' style="color:#' . $color . '"'; else $style = ' style="display:none"'; ?> <h1><a id="name"<?php echo $style; ?> onclick="return false;" href="<?php echo esc_url( home_url( '/' ) ); ?>"><?php bloginfo( 'name' ); ?></a></h1> <div id="desc"<?php echo $style; ?>><?php bloginfo( 'description' ); ?></div> <?php if ( $image ) : ?> <img src="<?php echo esc_url( $image ); ?>" alt="" /> <?php endif; ?> </div> <?php } endif; // newtheme_admin_header_image
[/codesyntax]
Esta función crea el código html que mostrará la imagen, el título y la descripción en su respectiva zona de opciones de la administración de WordPress, para que el usuario pueda ver como quedaría.
[codesyntax lang=»php»]
<?php /** * Sets the post excerpt length to 40 words. * * To override this length in a child theme, remove the filter and add your own * function tied to the excerpt_length filter hook. */ function newtheme_excerpt_length( $length ) { return 40; } add_filter( 'excerpt_length', 'newtheme_excerpt_length' );
[/codesyntax]
Esta función establece la longitud del extracto de un post a 40 palabras.
[codesyntax lang=»php»]
<?php /** * Returns a "Continue Reading" link for excerpts */ function newtheme_continue_reading_link() { return ' <a href="'. esc_url( get_permalink() ) . '">' . __( 'Continue reading <span class="meta-nav">→</span>', 'newtheme' ) . '</a>'; }
[/codesyntax]
Esta función devuelve el link con el texto «Seguir leyendo…» en los extractos de los posts.
[codesyntax lang=»php»]
<?php /** * Replaces "[...]" (appended to automatically generated excerpts) with an ellipsis and newtheme_continue_reading_link(). * * To override this in a child theme, remove the filter and add your own * function tied to the excerpt_more filter hook. */ function newtheme_auto_excerpt_more( $more ) { return ' …' . newtheme_continue_reading_link(); } add_filter( 'excerpt_more', 'newtheme_auto_excerpt_more' );
[/codesyntax]
Esta función remplaza el texto «[…]» por «…» utilizando «…» para ello, y el link de newtheme_continue_reading_link()–
[codesyntax lang=»php»]
<?php /** * Adds a pretty "Continue Reading" link to custom post excerpts. * * To override this link in a child theme, remove the filter and add your own * function tied to the get_the_excerpt filter hook. */ function newtheme_custom_excerpt_more( $output ) { if ( has_excerpt() && ! is_attachment() ) { $output .= newtheme_continue_reading_link(); } return $output; } add_filter( 'get_the_excerpt', 'newtheme_custom_excerpt_more' );
[/codesyntax]
Añade la salida de newtheme_continue_reading_link() a los extractos personalizados de los posts.
[codesyntax lang=»php»]
<?php /** * Get our wp_nav_menu() fallback, wp_page_menu(), to show a home link. */ function newtheme_page_menu_args( $args ) { $args['show_home'] = true; return $args; } add_filter( 'wp_page_menu_args', 'newtheme_page_menu_args' );
[/codesyntax]
Esta función hace que en nuestro menú de navegación aparezca un link hacía la página principal.
[codesyntax lang=»php»]
<?php /** * Register our sidebars and widgetized areas. Also register the default Epherma widget. */ function newtheme_widgets_init() { register_widget( 'New_Theme_Ephemera_Widget' ); register_sidebar( array( 'name' => __( 'Main Sidebar', 'newtheme' ), 'id' => 'sidebar-1', 'before_widget' => '<aside id="%1$s" class="widget %2$s">', 'after_widget' => "</aside>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); register_sidebar( array( 'name' => __( 'Showcase Sidebar', 'newtheme' ), 'id' => 'sidebar-2', 'description' => __( 'The sidebar for the optional Showcase Template', 'newtheme' ), 'before_widget' => '<aside id="%1$s" class="widget %2$s">', 'after_widget' => "</aside>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); register_sidebar( array( 'name' => __( 'Footer Area One', 'newtheme' ), 'id' => 'sidebar-3', 'description' => __( 'An optional widget area for your site footer', 'newtheme' ), 'before_widget' => '<aside id="%1$s" class="widget %2$s">', 'after_widget' => "</aside>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); register_sidebar( array( 'name' => __( 'Footer Area Two', 'newtheme' ), 'id' => 'sidebar-4', 'description' => __( 'An optional widget area for your site footer', 'newtheme' ), 'before_widget' => '<aside id="%1$s" class="widget %2$s">', 'after_widget' => "</aside>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); register_sidebar( array( 'name' => __( 'Footer Area Three', 'newtheme' ), 'id' => 'sidebar-5', 'description' => __( 'An optional widget area for your site footer', 'newtheme' ), 'before_widget' => '<aside id="%1$s" class="widget %2$s">', 'after_widget' => "</aside>", 'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>', ) ); } add_action( 'widgets_init', 'newtheme_widgets_init' );
[/codesyntax]
Esta función registra nuestro widget que crearemos en el archivo inc/widgets.php, y las cinco sidebars que añade el tema a diferentes partes de la página.
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'newtheme_content_nav' ) ) : /** * Display navigation to next/previous pages when applicable */ function newtheme_content_nav( $nav_id ) { global $wp_query; if ( $wp_query->max_num_pages > 1 ) : ?> <nav id="<?php echo $nav_id; ?>"> <h3 class="assistive-text"><?php _e( 'Post navigation', 'newtheme' ); ?></h3> <div class="nav-previous"><?php next_posts_link( __( '<span class="meta-nav">←</span> Older posts', 'newtheme' ) ); ?></div> <div class="nav-next"><?php previous_posts_link( __( 'Newer posts <span class="meta-nav">→</span>', 'newtheme' ) ); ?></div> </nav><!-- #nav-above --> <?php endif; } endif; // newtheme_content_nav
[/codesyntax]
Muestra los links para mostrar la siguiente o anterior página de posts cuando sea aplicable.
[codesyntax lang=»php»]
<?php /** * Return the URL for the first link found in the post content. * * @return string|bool URL or false when no link is present. */ function newtheme_url_grabber() { if ( ! preg_match( '/<a\s[^>]*?href=[\'"](.+?)[\'"]/is', get_the_content(), $matches ) ) return false; return esc_url_raw( $matches[1] ); }
[/codesyntax]
Devuelve la url del primer link encontrado en el contenido del post.
[codesyntax lang=»php»]
<?php /** * Count the number of footer sidebars to enable dynamic classes for the footer */ function newtheme_footer_sidebar_class() { $count = 0; if ( is_active_sidebar( 'sidebar-3' ) ) $count++; if ( is_active_sidebar( 'sidebar-4' ) ) $count++; if ( is_active_sidebar( 'sidebar-5' ) ) $count++; $class = ''; switch ( $count ) { case '1': $class = 'one'; break; case '2': $class = 'two'; break; case '3': $class = 'three'; break; } if ( $class ) echo 'class="' . $class . '"'; }
[/codesyntax]
Cuenta el número de sidebars habilitados para el pie de página y devuelve la clase que corresponda.
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'newtheme_comment' ) ) : /** * Template for comments and pingbacks. * * To override this walker in a child theme without modifying the comments template * simply create your own newtheme_comment(), and that function will be used instead. * * Used as a callback by wp_list_comments() for displaying the comments. * */ function newtheme_comment( $comment, $args, $depth ) { $GLOBALS['comment'] = $comment; switch ( $comment->comment_type ) : case 'pingback' : case 'trackback' : ?> <li class="post pingback"> <p><?php _e( 'Pingback:', 'newtheme' ); ?> <?php comment_author_link(); ?><?php edit_comment_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?></p> <?php break; default : ?> <li <?php comment_class(); ?> id="li-comment-<?php comment_ID(); ?>"> <article id="comment-<?php comment_ID(); ?>" class="comment"> <footer class="comment-meta"> <div class="comment-author vcard"> <?php $avatar_size = 68; if ( '0' != $comment->comment_parent ) $avatar_size = 39; echo get_avatar( $comment, $avatar_size ); /* translators: 1: comment author, 2: date and time */ printf( __( '%1$s on %2$s <span class="says">said:</span>', 'newtheme' ), sprintf( '<span class="fn">%s</span>', get_comment_author_link() ), sprintf( '<a href="%1$s"><time pubdate datetime="%2$s">%3$s</time></a>', esc_url( get_comment_link( $comment->comment_ID ) ), get_comment_time( 'c' ), /* translators: 1: date, 2: time */ sprintf( __( '%1$s at %2$s', 'newtheme' ), get_comment_date(), get_comment_time() ) ) ); ?> <?php edit_comment_link( __( 'Edit', 'newtheme' ), '<span class="edit-link">', '</span>' ); ?> </div><!-- .comment-author .vcard --> <?php if ( $comment->comment_approved == '0' ) : ?> <em class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.', 'newtheme' ); ?></em> <br /> <?php endif; ?> </footer> <div class="comment-content"><?php comment_text(); ?></div> <div class="reply"> <?php comment_reply_link( array_merge( $args, array( 'reply_text' => __( 'Reply <span>↓</span>', 'newtheme' ), 'depth' => $depth, 'max_depth' => $args['max_depth'] ) ) ); ?> </div><!-- .reply --> </article><!-- #comment-## --> <?php break; endswitch; } endif; // ends check for newtheme_comment()
[/codesyntax]
Esta función genera el código html necesario para mostrar cada comentario de un post.
[codesyntax lang=»php»]
<?php if ( ! function_exists( 'newtheme_posted_on' ) ) : /** * Prints HTML with meta information for the current post-date/time and author. * Create your own newtheme_posted_on to override in a child theme */ function newtheme_posted_on() { printf( __( '<span class="sep">Posted on </span><a href="%1$s" title="%2$s" rel="bookmark"><time class="entry-date" datetime="%3$s" pubdate>%4$s</time></a><span class="by-author"> <span class="sep"> by </span> <span class="author vcard"><a class="url fn n" href="%5$s" title="%6$s" rel="author">%7$s</a></span></span>', 'newtheme' ), esc_url( get_permalink() ), esc_attr( get_the_time() ), esc_attr( get_the_date( 'c' ) ), esc_html( get_the_date() ), esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ), esc_attr( sprintf( __( 'View all posts by %s', 'newtheme' ), get_the_author() ) ), get_the_author() ); } endif;
[/codesyntax]
Esta función devuelve los metadatos de un post.
[codesyntax lang=»php»]
<?php /** * Adds two classes to the array of body classes. * The first is if the site has only had one author with published posts. * The second is if a singular post being displayed */ function newtheme_body_classes( $classes ) { if ( function_exists( 'is_multi_author' ) && ! is_multi_author() ) $classes[] = 'single-author'; if ( is_singular() && ! is_home() && ! is_page_template( 'showcase.php' ) && ! is_page_template( 'sidebar-page.php' ) ) $classes[] = 'singular'; return $classes; } add_filter( 'body_class', 'newtheme_body_classes' );
[/codesyntax]
Esta función devuelve las clases de estilos que corresponden para la etiqueta body dependiendo del tipo de página que se muestre al usuario.
WordPress 3.x para desarrolladores: Convenciones
0Aunque es un tema cuanto menos, aburrido, es muy necesario a la hora de trabajar en grupo, o si vas a publicar tu plugin o plantilla en WordPress. Las convenciones son normas aplicadas al código para que todos los desarrolladores puedan interpretar el código sin muchos problemas. También por estética: queda más elegante un código con la misma tabulación (por ejemplo) en cada linea que, que cada programador ponga la tabulación que se le antoje. Sin más preámbulos vamos al tema:
COMILLAS SIMPLES Y DOBLES
[codesyntax lang=»php»]
<?php echo '<a href="/static/link" title="Yeah yeah!">Link name</a>'; echo "<a href='$link' title='$linktitle'>$linkname</a>"
[/codesyntax]
Si no tienes nada que evaluar en la cadena, pon comillas simples, sino comillas dobles.
SANGRÍA
Usa tabulaciones y no espacios.
[codesyntax lang=»php»]
<?php $foo = 'somevalue'; $foo2 = 'somevalue2'; $foo34 = 'somevalue3'; $foo5 = 'somevalue4';
[/codesyntax]
Los arrays asociativos deberían empezar en una linea nueva.
[codesyntax lang=»php»]
<?php $my_array = array( 'foo' => 'somevalue', 'foo2' => 'somevalue2', 'foo3' => 'somevalue3', 'foo34' => 'somevalue3', );
[/codesyntax]
LLAVES
En bloques multilinea se deben poner las llaves tal como sigue:
[codesyntax lang=»php»]
<?php if ( condition ) { action1(); action2(); } elseif ( condition2 && condition3 ) { action3(); action4(); } else { defaultaction(); }
[/codesyntax]
Si solo hay una linea en cada bloque se pueden omitir por brevedad.
[codesyntax lang=»php»]
<?php if ( condition ) action1(); elseif ( condition2 ) action2(); else action3();
[/codesyntax]
Si hay un bloque con más de una linea se deberán escribir con llaves:
[codesyntax lang=»php»]
<?php if ( condition ) { action1(); } elseif ( condition2 ) { action2a(); action2b(); }
[/codesyntax]
Los bucles deben contenerse siempre entre llaves:
[codesyntax lang=»php»]
<?php foreach ( $items as $item ) { process_item( $item ); }
[/codesyntax]
NO UTILIZAR LA ETIQUETA DE INICIO CORTA DE PHP
La forma correcta sería:
<?php ... ?>
NO CERRAR EL SCRIPT DE PHP CON SU ETIQUETA
Es decir en vez de usar:
<?php ... ?>
Usaremos solo la inicial
<?php ...
USO DEL ESPACIO
Pon espacios siempre después de las comas y en ambos lados de los operadores lógicos, de comparación, de cadenas y de asignación.
x == 23 foo && bar ! foo array( 1, 2, 3 ) $baz . '-5' $term .= 'X'
Pon espacios a ambos lados de los paréntesis de apertura y cierre.
foreach ( $foo as $bar ) { ...
Cuando definas una función, hazlo así:
function my_function( $param1 = 'foo', $param2 = 'bar' ) { ...
Al realizar comparaciones lógicas:
if ( ! $foo ) { ...
Cuando hagas una conversión de tipos:
foreach ( (array) $foo as $bar ) { ... $foo = (boolean) $bar;
Cuando se hace referencia a un elemento de un array, solo se incluyen espacios en blanco cuando es una variable:
$x = $foo['bar'];$x = $foo[ $bar ];
FORMATEO DE SENTENCIAS SQL
Las partes de la sentencia que sean palabras de SQL deben ir en mayusculas, como SELECT o WHERE.
Es recomendable usar el método $wpdb->prepare() para formatear la sentencia SQL. Este método añadirá las comillas a los valores que lo necesiten.
$var = "dangerous'"; // Los datos en crudo podrían o no necesitar ser formateados $id = some_foo_number(); // El dato que nosotros esperamos es un número, pero no estamos seguros $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->posts SET post_title = %s WHERE ID = %d", $var, $id ) );
%s se utiliza cuando el valor es una cadena (string) y %d cuando es un número. En el método prepare() se añaden las variables que se formatearán y añadirán a la consulta en orden.
CONVENCIONES DE NOMENCLATURAS
Usa letras minúsculas en variables y nombres de funciones. Separa las palabras con guiones bajos (_).
function some_name( $some_variable ) { [...] }
Los nombres de clases deben utilizar palabras capitalizadas separadas con guiones bajos. Las siglas deben estar en mayúsculas:
class Walker_Category extends Walker { [...] } class WP_HTTP { [...] }
Los archivos deben ser nombrados descriptivamente con letras minúsculas y las palabras deben separarse con guiones.
my-plugin-name.php
Los nombres de archivos de clase se basarán en el nombre de la clase precedido de class- y los guiones bajos de la clase serán sustituidos por guiones, por ejemplo WP_Error pasa a ser:
class-wp-error.php
VALORES DE PARÁMETROS DE FUNCIONES AUTOEXPLICATIVOS
Se prefieren valores de cadena que solo true y false cuando se llama a las funciones.
// Correcto function eat( $what, $speed = 'slowly' ) { ... } eat( 'mushrooms' ); eat( 'mushrooms', 'slowly' ); eat( 'dogfood', 'fast' );
OPERADOR TERNARIO
El operador ternario está bien, pero siempre que lo uses prueba que la sentencia sea verdad, no falsa. De la otra forma es confuso. En el caso de empty() se permite el uso de ! empty(), ya que es más legible.
// (si la sentencia es verdad) ? (hacer esto) : (sino, hacer esto); $musictype = ( 'jazz' == $music ) ? 'cool' : 'blah'; // (si el campo no está vacío ) ? (hacer esto) : (sino, hacer esto);
CONDICIONES YODA
if( true == $the_force ){ $victorious = you_will( $be ); }
Siempre que hagas comparaciones lógicas pon la variable en el lado derecho, la constante o el literal en el izquierdo.
Esto se utiliza para en el caso de que en vez de == pongas = (admítelo, más de una vez te habrá pasado), de esta manera saltará un error ya que no puedes asignar a una constante el valor de la variable.
Es un poco extraño, pero útil.
CÓDIGO LIMPIO
En general, la legibilidad es más importante que la limpieza o la brevedad.
isset( $var ) || $var = some_function();if ( ! isset( $var ) ) $var = some_function();
WordPress 3.x para desarrolladores: Introducción
0Después de varias semanas buscando información sobre WordPress para un proyecto que tenía pendiente (ya acabado), he observado que hay cierta escasez de información sobre el desarrollo de WordPress, ya que la mayoría de tutoriales o manuales que rondan por internet están limitados a la creación básica de plugins o a lo más básico de la creación de plantillas.
Por ello voy a realizar un tutorial que, basandome en el tema Twenty Eleven de WordPress permita conocer el funcionamiento de los temas y las plantillas. Para desarrollar la parte de los plugins se creará uno de ejemplo.
Muchos ejemplos de código serán de la documentación principal de WordPress y es la que deberías consultar más habitualmente si vas a desarrollar para WordPress: http://codex.wordpress.org/Main_Page
Durante las próximas semanas publicaré un tema por semana hasta que se complete el tutorial.
Cassandra 1.x y PHP para desarrolladores SQL: Clusters
2Cassandra permite crear anillos o clusters de servidores de una forma muy sencilla, esto nos permitirá levantar nuevos servidores dentro de un cluster en cuestión de varios minutos.
Para ello tendremos que modificar la configuración de la BD.
En /etc/cassandra modificamos el archivo cassandra.yaml. Buscaremos la siguiente línea:
- seeds: "localhost"
Y sustituimos localhost por la ip local del servidor, en mi caso 192.168.1.10.
- seeds: "192.168.1.10"
A continuación modificamos las siguientes líneas:
listen_address: localhost [...] rpc_address: localhost
Por:
listen_address: 192.168.1.10 [...] rpc_address: 192.168.1.10
Guardamos y reiniciamos el servidor.
Ahora el servidor con esta configuración será al que se conecten el resto de servidores del cluster.
Para el resto de servidores la configuración es parecida. En seeds mantenemos la ip del servidor principal y en listen_address y rpc_address ponemos la ip del servidor a unir al cluster:
- seeds: "192.168.1.10" [...] listen_address: 192.168.1.103 [...] rpc_address: 192.168.1.103
Utilizo la ip 192.168.1.103 ya que es la que tengo configurada en mi cluster de prueba, tu deberías poner la ip correspondiente a la máquina donde estés configurando Cassandra.
Guardamos y reiniciamos la BD.
Esto es todo lo que hay que hacer para crear un cluster con Cassandra
Cassandra 1.x y PHP para desarrolladores SQL: phpCassa (III)
4Ya he tratado casi en su totalidad las funciones más básicas de PHPCassa y Cassandra, con lo que ya tendrás un conocimiento suficientemente amplio de lo que se puede hacer con ellos, el resto dependerá de la evolución de la BD y de las librerías (y de la experiencia que tengas xP).
Hoy trataré varios temas que por las consultas realizadas por varios usuarios se merece un post aparte en el que se pueda tratar de una forma más amplia. Estos temas son: ordenar registros, crear keys para los registros y contar registros.
ORDENAR REGISTROS
Cassandra dispone de varios tipos de comparadores y subcomparadores para ordenar los registros. El más habitual es UTF-8 pero hay varios más. Si vamos a Cassandra Cluster Admin y accedemos al formulario de creación de columns family, podremos pasar el ratón por los interrogantes que hay a la izquierda de los campos para poder ver los diferentes tipos de comparadores:
Como puedes ver, estos comparadores le dicen a Cassandra como ordenar los registros. Si has seguido este tutorial ya conocerás al menos uno de los comparadores (utf-8) por tanto vamos a ver como ordena Cassandra los registros con este comparador.
Para este primer ejemplo vamos a crear una column family llamada column_family_order_utf8 de tipo standard y el tipo de comparador UTF8Type.
Vamos a nuestro archivo test.php y escribimos el siguiente código:
[codesyntax lang=»php»]
<?php $data = array(); $data[5] = array( 'title' => 'Apache Cassandra', 'license' => 'Open Source', 'category' => 'no-sql', ); $data[3] = array( 'title' => 'MongoDB', 'license' => 'Open Source', 'category' => 'no-sql' ); $data[1] = array( 'title' => 'Neo4j', 'license' => 'Open Source', 'category' => 'no-sql', ); $data[4] = array( 'title' => 'MySQL', 'license' => 'Open Source', 'category' => 'sql' ); $data[2] = array( 'title' => 'MariaDB', 'license' => 'Open Source', 'category' => 'sql', ); foreach($data as $key => $value){ $cass->guardar('column_family_order_utf8', $key, $value); }
[/codesyntax]
Este código guardará un array desordenado en nuestra column family. Una vez ejecutado el script accedemos a Cassandra Cluster Admin y visualizamos los registros de column_family_order_utf8, nos mostrará el siguiente resultado:
Como puedes observar los registros no se han ordenado, sin embargo cada una de las columns de cada registro sí están ordenadas por orden alfabético. Esto sucede porque los comparadores no ordenan por keys o claves de los registros sino por columns, aunque hay un caso especial, si la column family es super los registros si estarán ordenados. Veamoslo.
Creamos una column family llamada column_family_utf8_super con el tipo de comparador UTF8Type y el tipo de column family como super. En nuestro archivo test.php añadimos el siguiente código:
[codesyntax lang=»php»]
<?php $data = array(); $data[5] = array( 'title' => 'Apache Cassandra', 'license' => 'Open Source', 'category' => 'no-sql', ); $data[3] = array( 'title' => 'MongoDB', 'license' => 'Open Source', 'category' => 'no-sql' ); $data[1] = array( 'title' => 'Neo4j', 'license' => 'Open Source', 'category' => 'no-sql', ); $data[4] = array( 'title' => 'MySQL', 'license' => 'Open Source', 'category' => 'sql' ); $data[2] = array( 'title' => 'MariaDB', 'license' => 'Open Source', 'category' => 'sql', ); $cass->guardar('column_family_order_utf8_super', 'databases', $data);
[/codesyntax]
Una vez ejecutado este script nos vamos a nuestra column family y nos mostrará lo siguiente:
Como puedes observar ahora sí están ordenados los registros, pero claro ahora están dentro de una super column.
En Cassandra la ordenación se realiza a las columnas del registro o los registros dentro de las super columns, si creasemos otra super column, esta no se ordenaría con respecto a la ya creada, ‘databases’.
Aunque esta ordenación puede ser útil y totalmente funcional, para los desarrolladores que vengan de las bases de datos relacionales les puede resultar confuso. Por ejemplo, para guardar los comentarios de un post de un blog podríamos utilizar este tipo de ordenación perfectamente, ya que podemos utilizar el id del post como key de la super column (el ‘databases’ de la imagen anterior se sustituiría por el id del post) y el timestamp (como este 1337787675.32246500) para la key de los registros. De esta forma tendríamos ordenados los comentarios por tiempo y por post. Si quisieramos recuperar los comentarios de un post concreto solo tendríamos que pasarle al método correspondiente el id del post como key de la super column.
¿Y si quisieramos guardar los post del blog? En este caso una column family super nos lo podría resolver indicando como key de la super column ‘posts‘ y utilizando como key en los registros el timestamp. Pero si quisieramos hacer busquedas utilizando indices secundarios una column family super no nos valdría, ya que los indices secundarios no funcionan en ellas.
Para ello habría que crear una column family standard para los post, que nos permitirá usar los indices secundarios, y una column family super para guardar las keys de los post dentro de una super column con key, por ejemplo, ‘key_posts‘. Para hacer la consulta habría que recuperar las keys de los posts a mostrar en primer lugar, y después, utilizando un método de PHPCassa que aun no hemos usado recuperar los registros correspondientes a esas keys.
El método que deberíamos añadir a nuestro archivo cassandra.php sería el siguiente:
[codesyntax lang=»php»]
<?php function obtenerMultiplesRegistros($name_columnFamily, $multiKeys, $super_column = ''){ if (!empty($super_column)){ $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily); $result = $column_family->multiget_super_column($multiKeys, $super_column); } else{ $column_family = new ColumnFamily($this->conexion, $name_columnFamily); $result = $column_family->multiget($multiKeys); } return $result; }
[/codesyntax]
A este método le pasamos el nombre de la column family standard donde hemos guardado los posts y un array con las keys a recuperar, nos devolverá un array con los datos de cada uno de los posts que le hemos pedido… y en el orden en el que le hayamos pasado las keys a recuperar.
Existe otra forma de ordenar registros, pero además de que en versiones posteriores de Cassandra desaparecerá y provoca problemas de rendimiento, yo no la recomiendo, ya que pierdes todos los beneficios que ofrece Cassandra. Aun así os dejo un link para que le echéis un ojo xD:
http://ria101.wordpress.com/2010/02/22/cassandra-randompartitioner-vs-orderpreservingpartitioner/
Y os dejo otro link para que tengais algo más de información respecto a ordenar registros en Cassandra:
http://ayogo.com/blog/2010/04/09/sorting-in-cassandra/
CREAR CLAVES O KEYS PARA LOS REGISTROS
Como has podido ver en el apartado anterior, para ordenar los registros es muy importante tener una key de cada registro que sea única y siempre vaya en orden. Esto las bases de datos relacionales nos lo dan ya hecho, sin embargo en las bases de datos no-sql esto no es así.
Las bases de datos no-sql se crearon para optimizar la lectura y escritura de los registros en la base de datos, esto provocó que algunas funcionalidades muy útiles en las bases relaciones no tuvieran cabida en las no-sql. Por tanto para mantener en orden los registros debemos crear nosotros nuestras propias claves.
PHPCassa dispone de un método para crear una clave aleatoria basada en el timestamp.
Para utilizarla primero añadiremos la clase a nuestra lista:
[codesyntax lang=»php» highlight_lines=»11″]
<?php use phpcassa\Connection\ConnectionPool; use phpcassa\ColumnFamily; use phpcassa\SuperColumnFamily; use phpcassa\ColumnSlice; use phpcassa\SystemManager; use phpcassa\Schema\StrategyClass; use phpcassa\Index\IndexExpression; use phpcassa\Index\IndexClause; use phpcassa\UUID;
[/codesyntax]
Ahora crearemos un nuevo método en nuestro archivo cassamdra.php que devolverá la clave:
[codesyntax lang=»php»]
<?php public function obtenerUuid(){ $util = new UUID; return $util->import($util->uuid1()); }
[/codesyntax]
Como me está quedando un post muy largo os voy a dejar algo de deberes xD. Sería interesante probarlo tanto con column families standard y super, además de con un tipo de comparador UTF8Type y TimeUUIDType.
Como el chorro de letras y números que devuelve es muy poco legible yo suelo utilizar mi propio sistema de claves, normalmente utilizo el microtime() de php y un par de ids de lo que se esté guardando: el id del usuario, el id de lo que se ha creado, etc. Algo que lo diferencie del resto. Para la clave primero pongo los segundos que devuelve microtime() y después los microsegundos. Para que os hagais una idea sería algo así:
$key = $segundos . ‘.’ . $microsegundos . ‘_’ . $id_post . ‘_’ . $id_usuario;
De esta forma le estamos dando una clave para los ejemplos del anterior apartado, más concretamente para los comentarios en un post.
CONTAR REGISTROS
El último apartado de este post. Contar registros. Esto es algo que Cassandra no lleva muy bien, sobre todo con grandes cantidades de información.
Cassandra cuando recibe una petición de lectura/escritura utiliza unas tablas en memoria llamadas memtables (el que le puso el nombre de rompió la cabeza pensando). Cuantas más peticiones reciba Cassandra más memtables creará, de esta forma permitirá una cierta consistencia de la información almacenada en la base de datos.
Cuando le pedimos a phpCassa que nos devuelva el número de registros en una column family o en una super column concreta, lo que está haciendo en realidad es hacer una petición a Cassandra de todos los registros que haya en la column family o en la super column. Cuando esto ocurre Cassandra guardará estos registros en la RAM del servidor antes de enviarlos a phpCassa, y sí Cassandra no cuenta los registros, porque no está pensada para eso, es phpCassa la que cuenta los registros y te devuelve el número concreto.
El método que utiliza phpCassa para contar registros es el que os muestro a continuación, dentro de un método para añadir al archivo cassandra.php:
[codesyntax lang=»php»]
<?php public function contar_registros($name_columnFamily, $key, $super_column='', $range_start='', $range_end=''){ $column_slice = new ColumnSlice($range_start, $range_end); if (!empty($super_column)){ $column_family = new SuperColumnFamily($this->conexion, $name_columnFamily); $result = $column_family->get_subcolumn_count($key, $super_column, $column_slice); } else{ $column_family = new ColumnFamily($this->conexion, $name_columnFamily); $result = $column_family->get_count($key, $column_slice); } return $result; }
[/codesyntax]
Esta forma de contar registros provoca que Cassandra consuma todos los recursos de RAM del servidor, con lo que no os la recomiendo.
La mejor manera de contar registros con Cassandra es utilizar una column family con contadores, de tal forma que en nuestro código cada vez que se guarde un registro en la bd se aumente el contador que lleva la cuenta de los registros guardados. En el caso de que se eliminen, habría que disminuirlo. Y en el caso de que el registro se esté actualizando controlar que no aumente el contador xD.
Cualquier duda que tengais intentaré responderla lo mejor posible en los comentarios.