Back-End

25 out, 2012

Como usar custom post types no WordPress para adicionar eventos ao seu site

Publicidade

Um dos recursos mais interessantes (e úteis) do WordPress são os custom post types. Como o nome sugere, o WordPress permite que você defina seus próprios tipos de posts, que são tratados como os já existentes (ou seja, mensagens e páginas).

Por exemplo, recentemente eu estava desenvolvendo um site que precisava criar e publicar eventos. Depois de pesquisar, encontrei um ótimo artigo do Noel Tock sobre como usar os custom post types para criar eventos.

Mesmo que o Noel tenha feito um grande trabalho explicando o conceito e o layout da abordagem, ele deixou algumas coisas de fora. Então, decidi escrever meu próprio guia um pouco mais abrangente para o uso de custom post types para criar eventos.

Como os eventos deveriam funcionar?

Antes de mergulhar nos detalhes da implementação, vamos falar primeiro sobre requisitos. Vamos imaginar que você está construindo um site para alguém que gostaria de criar e publicar eventos. Como ele poderia ser?

Bem, antes de qualquer coisa, existiria uma nova categoria de coisas em WordPress chamada Eventos:

Segundo, não existiria uma maneira fácil de ver o que os Eventos criaram (como posts ou páginas):

E é claro que existiria uma maneira fácil de adicionar um novo evento e especificar os detalhes dele, como data e local:

Também seria bom ser capaz de incorporar uma lista de eventos dentro de uma página ou um post, talvez usando o código que tenha esta aparência:

<h2>upcoming events</h2>
[events daterange="current"]

<h2>past events</h2>
[events daterange="past"]

Finalmente, seria ótimo ter um template separado para exibir eventos individuais.

Ok, mas como podemos fazer isso?

A fim de construir uma funcionalidade abrangente e amigável para gerenciar eventos, precisaremos implementar o seguinte:

  1. Registrar um novo custom post type chamado Eventos
  2. Adicionar suporte para a exibição de listas de Eventos
  3. Adicionar suporte para adição e a edição de Eventos individuais
  4. Adicionar um shortcode para incluir listas de eventos em posts e páginas
  5. Adicionar uma página especial que possa exibir um evento individual

Vamos discutir cada uma delas em detalhes.

1. Registrar events post type

A primeira coisa que você precisa fazer é registrar event post type com WordPress. Para isso, vamos precisar modificar o arquivo functions.php e adicionar o seguinte código:

add_action('init', 'event_register');

function event_register() {

$labels = array(
'name' => _x('Events', 'post type general name'),
'singular_name' => _x('Event', 'post type singular name'),
'add_new' => _x('Add New', 'event'),
'add_new_item' => __('Add New Event'),
'edit_item' => __('Edit Event'),
'new_item' => __('New Event'),
'view_item' => __('View Event'),
'search_items' => __('Search Events'),
'not_found' =>  __('Nothing found'),
'not_found_in_trash' => __('Nothing found in Trash'),
'parent_item_colon' => ''
);

$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'query_var' => true,
'rewrite' => true,
'capability_type' => 'post',
'hierarchical' => false,
'menu_position' => null,
'supports' => array('title','editor','thumbnail')
);

register_post_type( 'events' , $args );
}

O array $labels diz ao WordPress como várias novas ações em torno de eventos devem ser chamadas, enquanto o array $args especifica como os eventos devem ser tratados. Por uma questão de brevidade, não vou entrar em detalhes sobre os parâmetros que você precisa especificar (você pode encontrar isso aqui).

2. Exibir listas de eventos

Para exibir uma lista de eventos para o usuário, nós precisamos fazer o seguinte:

Para a minha lista de eventos, eu queria mostrar a data do evento, juntamente com início e término, localização e cidade. Aqui está o código para fazer isso:

add_action("manage_posts_custom_column",  "events_custom_columns");
add_filter("manage_events_posts_columns", "events_edit_columns");

function events_edit_columns($columns){
$columns = array(
"cb" => "<input type=\"checkbox\" />",
"title" => "Event",
"event_date" => "Event Date",
"event_location" => "Location",
"event_city" => "City",
);
return $columns;
}

function events_custom_columns($column){
global $post;
$custom = get_post_custom();

switch ($column) {
case "event_date":
echo format_date($custom["event_date"][0]) . '<br /><em>' .
$custom["event_start_time"][0] . ' - ' .
$custom["event_end_time"][0] . '</em>';
break;

case "event_location":
echo $custom["event_location"][0];
break;

case "event_city":
echo $custom["event_city"][0];
break;
}
}

O código é bastante simples. A primeira função atribui etiquetas e nomes de cada uma das colunas que eu pretendo exibir, enquanto a segunda função formata o conteúdo de cada coluna.

Adicionar colunas classificáveis

Para tornar a lista ainda melhor, poderíamos fazer colunas classificáveis. Nesse caso, a possibilidade de ordenar a data do evento é um recurso muito útil. Para isso, temos que:

  • adicionar um filtro para indicar qual a coluna é classificável
  • definir como a classificação deve acontecer

Aqui está o código:

add_filter("manage_edit-events_sortable_columns", "event_date_column_register_sortable");
add_filter("request", "event_date_column_orderby" );

function event_date_column_register_sortable( $columns ) {
$columns['event_date'] = 'event_date';
return $columns;
}

function event_date_column_orderby( $vars ) {
if ( isset( $vars['orderby'] ) && 'event_date' == $vars['orderby'] ) {
$vars = array_merge( $vars, array(
'meta_key' => 'event_date',
'orderby' => 'meta_value_num'
) );
}
return $vars;
}

3. Editar eventos

Ok, a próxima coisa que precisamos fazer é adicionar a capacidade de editar eventos. Mais especificamente, nós precisamos adicionar propriedades personalizadas para a tela normal de edição de posts para que o usuário possa obter detalhes adicionais de entrada do evento (como data e local). Eis do que você precisa:

  • adicionar uma meta box Event Details
  • adicionar ação para salvar detalhes do evento

O código para adicionar a meta box Event Details se parece com este:

add_action("admin_init", "events_admin_init");

function events_admin_init(){
add_meta_box("event_meta", "Event Details", "event_details_meta", "events", "normal", "default");
}

function event_details_meta() {

$ret = '<p><label>Date: </label><input type="text" name="event_date" value="' . format_date(get_event_field("event_date")) . '" /><em>(mm/dd/yyy)</em>';
$ret = $ret . '</p><p><label>Start Time: </label><input type="text" name="event_start_time" value="' . get_event_field("event_start_time") . '" /><em>(hh:mm pm)</em></p>';
$ret = $ret . '<p><label>End Time: </label><input type="text" name="event_end_time" value="' . get_event_field("event_end_time") . '" />    <em>(hh:mm pm)</em> </p>';
$ret = $ret . '<p><label>Location: </label><input type="text" size="70" name="event_location" value="' . get_event_field("event_location") . '" /></p>';
$ret = $ret . '<p><label>Street: </label><input type="text" size="50" name="event_street" value="' . get_event_field("event_street") . '" /></p>';
$ret = $ret . '<p><label>City: </label><input type="text" size="50" name="event_city" value="' . get_event_field("event_city") . '" /></p>';
$ret = $ret . '<p><label>Location URL: </label><input type="text" size="70" name="event_location_url" value="' . get_event_field("event_location_url") . '" /></p>';
$ret = $ret . '<p><label>Register URL: </label><input type="text" size="70" name="event_register_url" value="' . get_event_field("event_register_url") . '" /></p>';

echo $ret;
}

A ação admin_init diz ao WordPress também chamar events_admin_init() sempre que um evento é adicionado ou editado. Isso, por sua vez, adiciona uma meta box Event Details por meio da chamada add_meta_box(). Finalmente, o evento real da caixa de Event Details é exibido usando a função event_details_meta().

Para tornar o código um pouco mais legível, eu defini uma função get_event_field(), que retorna o valor de um campo de evento, se ele existir:

function get_event_field($event_field) {
global $post;

$custom = get_post_custom($post->ID);

if (isset($custom[$event_field])) {
return $custom[$event_field][0];
}
}

Salvando detalhes do evento

Nós também precisamos adicionar código para salvar os detalhes do evento inseridos pelo usuário. Isso é realizado através da adição de uma ação para save_post:

add_action('save_post', 'save_event_details');

function save_event_details(){
global $post;

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;

if ( get_post_type($post) == 'event')
return;

if(isset($_POST["event_date"])) {
update_post_meta($post->ID, "event_date", strtotime($_POST["event_date"]));
}

save_event_field("event_start_time");
save_event_field("event_end_time");
save_event_field("event_location");
save_event_field("event_street");
save_event_field("event_city");
save_event_field("event_location_url");
save_event_field("event_register_url");
}

A função de memória não é complicada, mas faz algumas coisas muito importantes. Primeiro, assegura que o recurso autosave do WordPress não perca campos personalizados. Em segundo lugar, ele garante que este save não vai funcionar se o tipo de evento não for post-type (ou seja, mensagens normais e páginas).

A propósito, note que eu converti o campo event_time dentro de um timestamp Unix antes de salvá-lo (isso foi uma das ótimas dicas do artigo do Noel). Fazer isso torna muito mais fácil trabalhar com datas posteriores, especialmente para coisas como classificação.

Por último, escrevi uma pequena função helper para tornar mais fácil salvar os campos:

function save_event_field($event_field) {
global $post;

if(isset($_POST[$event_field])) {
update_post_meta($post->ID, $event_field, $_POST[$event_field]);
}
}

4. Exibir eventos

A maneira mais simples para permitir que listas de eventos sejam facilmente incluídas nas páginas ou nos posts é através da definição um shortcode. E porque shortcodes podem ser parametrizados, você pode usar o mesmo para retornar os eventos que virão e os passados. Aqui está o código para fazê-lo:

add_shortcode( 'events', 'get_events_shortcode' );

function get_events_shortcode($atts){
global $post;

// get shortcode parameter for daterange (can be "current" or "past")
extract( shortcode_atts( array(
'daterange' => 'current',
), $atts ) );

ob_start();

// prepare to get a list of events sorted by the event date
$args = array(
'post_type' => 'events',
'orderby'   => 'event_date',
'meta_key'  => 'event_date',
'order'     => 'ASC'
);

query_posts( $args );

$events_found = false;

// build up the HTML from the retrieved list of events
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
$event_date = get_post_meta($post->ID, 'event_date', true);

switch ($daterange) {
case "current":
if ($event_date >= time() ) {
echo get_event_container();
$events_found = true;
}
break;

case "past":
if ($event_date < time() ) {
echo get_past_event_summary();
$events_found = true;
}
break;
}
}
}

wp_reset_query();

if (!$events_found) {
echo "<p>no events found.</p>";
}

$output_string = ob_get_contents();
ob_end_clean();

return $output_string;
}

Há um monte de coisas acontecendo nessa função, e a maioria é bem feia. Algumas coisas que vale a pena ressaltar:

  • Eu estou usando o buffer de saída com ob_start() para capturar a saída e exibi-la de uma só vez (outra grande dica do Noel).
  • Porque eu armazeno event_time como um timestamp Unix, classificar eventos usando o campo de data é tão simples como especificar como o valor order_by.

A propósito, aqui estão as funções helper get_event_container() e get_past_event_summary():

function get_event_container() {
global $post;
$ret = '<section>';
$ret =  $ret . get_event_calendar_icon() . '<section>';
$ret = $ret .  get_event_details(false, true);
$ret =  $ret . '</section></section>';

return $ret;
}

function get_past_event_summary() {
global $post;
$ret = '<section>';
$ret =  $ret . '<h3>' . $post->post_title . '</h3><p>';
$ret = $ret . '<h4>' . get_post_meta($post->ID, 'event_city', true) .'</h4>';
$ret = $ret .  '<em>' . format_date(get_post_meta($post->ID, 'event_date', true)) . '</em>';
$ret =  $ret . '</p></section>';

return $ret;
}

5. Exibir eventos individuais

Por fim, para exibir um evento individual, é possível definir um template especial chamado single-events.php. Eis o que pode parecer:

<?php get_header(); ?>

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

<article id="event-<?php the_ID(); ?>">
<h1><?php the_title(); ?></h1>
<section>
<?php echo get_event_calendar_icon(); ?>
<section>
<?php the_content('Read more on "'.the_title('', '', false).'" &raquo;'); ?>
<?php echo get_event_details(true, false); ?>
</section>
</section>
</article>
<?php endwhile; endif; ?>

<?php get_footer(); ?>

Depois de ir para o loop padrão do WordPress, eu fiz um article que contém o nome do evento como o cabeçalho, um pequeno pedaço de código HTML para exibir a data e algumas informações adicionais sobre o evento.

Apenas para completar a imagem, aqui estão as funções helper get_event_calendar_icon() e get_event_details():

function get_event_calendar_icon() {
global $post;
$unixtime = get_post_meta($post->ID, 'event_date', true);
$month = date("M", $unixtime);
$day = date("d", $unixtime);
$year = date("y", $unixtime);
return  '<div>' . $day . '<em>' . $month . '</em></div>';
}

function get_event_details($include_register_button, $include_title) {
global $post;
$unixtime = get_post_meta($post->ID, 'event_date', true);
$location_url = get_post_meta($post->ID, 'event_location_url', true);
$register_url = get_post_meta($post->ID, 'event_register_url', true);

$ret = '';
if ($include_title) {
$ret =  $ret . '<h3><a href="' . get_permalink() . '">' . $post->post_title . '</a></h3>';
}

$ret = $ret . '<p><h4>'.get_post_meta($post->ID, 'event_location', true) . '</h4>';
$ret = $ret . format_possibly_missing_metadata('event_street');
$ret = $ret . format_possibly_missing_metadata('event_city');
$ret = $ret . '</p><p>';
$ret = $ret . date("F d, Y", $unixtime) . '<br/>';
$ret = $ret . '<em>' . get_post_meta($post->ID, 'event_start_time', true) . ' - ';
$ret = $ret . get_post_meta($post->ID, 'event_end_time', true) . '</em>';

if (!empty($register_url) && $include_register_button && $unixtime > time()) {
$ret = $ret .'<a href="' . $register_url . '">register</a>';
}

return $ret;
}

function format_possibly_missing_metadata($field_name) {
global $post;
$field_value = get_post_meta($post->ID, $field_name, true);

if (!empty($field_value)) {
return $field_value.'<br/>';
}
}

Sem entrar em muitos detalhes, cada função apenas retorna uma parte de HTML contendo metadados sobre os eventos. Caso você esteja querendo saber como estilizar HTML com CSS3 para ele ficar como um ícone de calendário, aqui está um ótimo tutorial do CSS Globe.

Pensamento final

Apesar de dar um pouco de trabalho para conseguir fazer isso, o resultado final funciona bem. O produto acabado em ação pode ser conferido nesta página.

***

Texto original disponível em http://tatiyants.com/how-to-use-wordpress-custom-post-types-to-add-events-to-your-site/