Categorias
Web

WooCommerce: como alinhar verticalmente os botões de compra

O WooCommerce conta agora com blocos que facilitam a criação de páginas personalizadas de produtos e uma das vantagens ao usar os blocos é a facilidade de alinhar o último elemento (por padrão, o botão) de cada produto listado.

Baita mão na roda

Essa opção, porém, não está disponível para sites ainda utilizando o shortcode [products] Nesse caso, ou você usa um plugin como o Woo Align Buttons ou adiciona um código CSS ao seu site:

/* WooCommerce Products Shortcode: bottom-align buttons -- https://wp.me/paOFn3-TO */
@media screen and (min-width: 768px) {  
  ul.products {
    display: flex;
    flex-wrap: wrap;
  }
   
  ul.products li.product {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
  }
   
  ul.products li.product .button {
    align-self: center;
  }
}

E segue o resultado:

Imagens que trazem paz: botões propriamente alinhados

Caso queira mudar o alinhamento dos botões, mude o valor do align-self para um outro qualquer.

Categorias
Web

Trabalhando com usuários no WordPress.com: minha palestra no 12º Curitiba WordPress meetup

No dia 20/07, eu dei uma palestra no 12º Curitiba WordPress meetup onde falei um pouco sobre a Automattic, o meu atual trabalho como Happiness Engineer e sobre o processo de seleção dentro da empresa. Foi uma conversa longa (quase 2 horas intercaladas com ótimas questões) e o pessoal pareceu bastante interessado no trabalho de suporte a usuário.

Entre os tópicos tratados, estavam:

  • A Automattic como uma empresa distribuída
  • Trabalhando com suporte – como é o dia-a-dia de um Happiness Engineer
  • O processo de recrutamento (antes, durante e depois do teste)
  • Trabalho remoto

Abaixo, os slides da conversa:

Categorias
Web

Como usar o ícone do site como logo no formulário de login do WordPress

Caso você já tenha cadastrado um Ícone do siteSite Icon em sua instalação do WordPress (a opção está presente a partir da versão 4.3), é possível transportar a imagem para a sua página de login. Para isso, adicione o código abaixo ao seu arquivo functions.php:

<?php
/**
* Displays the registered Site Icon as a logo on the Login Form
*/
function fltnt_add_site_icon_to_login() {
if ( function_exists( 'has_site_icon' ) && has_site_icon() ) {
?>
<style type="text/css">
.login h1 a {
background-image: url(<?php site_icon_url(); ?>);
}
</style>
<?php
}
}
add_action( 'login_enqueue_scripts', 'fltnt_add_site_icon_to_login' );

 

Meus sinceros agradecimentos ao Hipster Logo Generator pelas ferramentas que me permitiram fazer tamanha obra de arte.


Veja também

 

Categorias
Web

Criando colunas condicionais de widgets com o Foundation

Widgets podem ser incômodos quando devem funcionar como colunas de informação. Pense em um rodapé que, por sua escolha, acomode também uma área de widgets. Você pode definir que o seu rodapé tratará 4 widgets em colunas, declarando cada um deles com 25% do tamanho total da sua área. Basta que ninguém adicione um quinto elemento ou, pior, remova um desses widgets, deixando aquela irregularidade desgraçada na tela. Você pode também usar uma biblioteca como o Masonry (o tema Twenty Thirteen usava ela, não?), mas será que seria necessário? Obviamente, existem formas mais suaves de se fazer isso.

Resolvi abordar o Foundation aqui pela oportunidade atual. Pretendo porém, num próximo artigo, mostrar como é possível fazer esses condicionais sem depender de um framework como ele ou o Bootstrap.

Basicamente, o que a solução faz é adicionar classes específicas aos widgets (usando a global $wp_registered_widgets) que atendam a determinadas condições. Ao contar o número de widgets em uma sidebar – que chamo aqui de widget areas –, adicionamos uma série de outras classes que irão controlar o posicionamento dos widgets. A única exceção fica por conta da minha única sidebar de verdade, chamada de sidebar-main: nela, widgets em colunas não são necessários.

Você pode até mesmo definir que, em uma certa sidebar, seus widgets fiquem com colunas de tamanhos diferentes. No meu caso, não exemplificado no gist abaixo, acabei jogando essa assimetria quando minha sidebar possuía apenas dois widgets. Assim, a primeira coluna ficou com uma largura maior (.medium-8) e a segunda preencheu o resto do grid do Foundation (.medium-4). O resultado é interessante justamente por fugir dos blocos de informação com tamanhos idênticos .

Um pequeno detalhe: esta solução irá, a princípio, gerenciar layouts em coluna quando o número de widgets na área for de no máximo seis, sem incluir o 5º. Para números maiores que seis, os widgets ficarão em sua própria linha. Isso, claro, também pode ser melhorado.

<?php
/**
* Loop through widget areas and add custom classes for each one of them
*
* @link http://colourstheme.com/2015/03/add-class-to-first-and-last-widget/ Reference #1
* @link https://gist.github.com/slobodan/6156076 Reference #2
*/
function fltnt_add_widget_custom_classes() {
global $wp_registered_widgets;
// Find those widgets
$sidebars = wp_get_sidebars_widgets();
if ( empty ( $sidebars ) ) {
return;
}
// Loop through each widget area
foreach ( $sidebars as $sidebar_id => $widgets ) {
// Our main sidebar doesn't need additional classes
if ( 'sidebar-main' == $sidebar_id ) {
continue;
}
// Get the number of widgets on the sidebar
$number_of_widgets = count( $widgets );
foreach ( $widgets as $i => $widget_id ) {
$widget_classes = '';
$widget_position = ( $i + 1 );
// Add a class for widget position
$widget_classes .= ' widget-position-' . $widget_position;
// Add a class for the total number of widgets in this widget area
$widget_classes .= ' widget-count-' . $number_of_widgets;
// Add first widget class
if ( 1 == $widget_position ) {
$widget_classes .= ' widget-first';
}
// Add last widget class
if ( $number_of_widgets == $widget_position ) {
$widget_classes .= ' widget-last';
}
// Add specific Foundation classes for layouts with, respectively, 6, 4, 3 or 2 columns
if ( 6 == $number_of_widgets ) {
$widget_classes .= ' medium-2';
}
elseif ( 4 == $number_of_widgets ) {
$widget_classes .= ' medium-3';
}
elseif ( 3 == $number_of_widgets ) {
$widget_classes .= ' medium-4';
}
elseif ( 2 == $number_of_widgets ) {
$widget_classes .= ' medium-6';
}
else {
$widget_classes .= ' medium-12';
}
// Add Foundation columns
$widget_classes .= ' columns';
// Save new classes into global $wp_registered_widgets
$wp_registered_widgets[$widget_id]['classname'] .= $widget_classes;
}
}
}
add_action( 'init', 'fltnt_add_widget_custom_classes' );

 

Talvez com os Block Grids também seja possível de fazer a brincadeira. A conferir.

Categorias
Web

Prototipação com Jekyll e Foundation: um pequeno estudo para partidos políticos


Uma ótima atualização: pelo visto, o Foundation 6 virá com essa ideia já embutida


 

Uma discussão recorrente entre mim e meus amigos é a questão da prototipação de um site. Como mostrar um wireframe que reflita o uso do site? Como que essa estrutura montada pudesse ser utilizada como começo de algo real? E, para este específico caso, como fazer isso de forma aberta?

Há inúmeras ferramentas para criação de wireframes: Axure, iPlotz, Balsamiq e, mais recentemente, plataformas robustas como Macaw, Webflow e UXPin. Tive contato com algumas, já por outras eu passei batido. Em outros momentos, tentei fazer pequenos wireframes funcionais diretamente em uma estrutura de tema do WordPress com a ajuda de algum framework como Bootstrap ou Foundation e gostei do resultado — o cliente consegue ver o site tomando forma, dos tons de cinza do wireframe à aplicação da sua identidade, isso tudo usando conteúdo de verdade. Neste caso, porém, estamos tratando de um projeto menos específico.

A idéia

Comecei a trabalhar em um tema para WordPress voltado a partidos políticos. O Podemos, partido de esquerda espanhol, está sendo usado como referência; não tanto na parte técnica (o site é feito em WordPress e usa o Avada, o tema mais vendido do ThemeForest), mas nas questões de informação, abordagem ao (e)leitor, áreas de interação, financiamento coletivo e transparência das contas. Ah, e por ser de esquerda.

Não satisfeito com as ideias de wireframes de tela, pulei para algo mais palpável, por mais estranho que seja tratar um site através desse adjetivo. O GitHub, por ser o padrão hoje para desenvolvimento e colaboração com código, foi uma escolha natural. A decisão pelo Jekyll, o gerador de sites estáticos, também segue o mesmo caminho: ele é automaticamente processado pelo GitHub dentro da branch gh-pages. Para os grids e estilo base, o escolhido foi o Foundation.

Por falta de uma ideia melhor, o projeto foi publicado sob a alcunha de PRJ. Melhor que o nome, talvez, sejam alguns dos pontos positivos:

  • Funcionalidade: o wireframe é navegável e fácil de se fazer
  • Avaliação imediata do cliente: com a publicação do wireframe diretamente na branch gh-pages, as mudanças já estão disponíveis para comentários e sugestões
  • Reuso: uma estrutura e um estilo base que poderão ser replicados no próprio tema
  • Código aberto, ideias abertas: construir colaborativamente o projeto não é um objetivo, mas parte do processo

Mas nada aparece sem alguns poréns. Ainda há muito conteúdo sendo tratado como código, verdade, e eu poderia usar o Jekyll de forma mais inteligente. Ademais, existe uma certa redundância, já que eu crio páginas e atribuo a elas o layout desejado. Isso tudo, acredito eu, é uma questão de atualização do processo.

Para amanhã

Alguns possíveis próximos passos:

  • Criar um repositório para uma base que possa ser trabalhada separadamente
  • Automatizar tarefas usando um task runner. Definir tarefas de deploy da gh-pages, por exemplo, facilitaria a atualização
  • Criar uma tarefa para substituir as tags do Jekyll pelas do WordPress. Assim, elementos como {% include header.html %}{% include header.html %}{% include header.html %} poderiam, respectivamente, se tornar <?php get_header(); ?><?php get_footer(); ?><?php get_sidebar(); ?>
  • Unir no mesmo repositório wireframe e tema, usando a branch gh-pages para manter online o protótipo

Visite o projeto PJR no GitHub.

 

Categorias
Web

WordCampus: uma ideia para uma conferência sobre WordPress com foco em instituições de ensino superior.

Eu gostaria muito de ver isso aqui no Brasil.

Categorias
Web

Focus v2

A proposta é que a funcionalidade já esteja disponível para a versão 4.1 do WordPress.

Categorias
Web

WordPress 3.8: trocando a cor da barra de administração no front end

A versão 3.8 do WordPress teve seu lançamento ontem, acompanhada de uma série de mudanças visuais bacanas: tipografia melhorada, novo gerenciador de temas, o uso da fonte Open Sans como padrão e um tapa geral no Painel, que agora conta também com oito esquemas de cores pra você escolher.

BEHOLD
BEHOLD

No entanto, mesmo definindo um esquema diferente de cores, a barra de administração no front end se mantém com a cor padrão cinza escuro / azul. Talvez por eu ter gostado tanto de escolher entre os bonitos esquemas de cores, achei válido que essa decisão fosse também, por que não, para a capa do site. Fazer isso é bem tranquilo com algumas poucas linhas de código no seu arquivo functions.php:

function admin_bar_color () {
	// Verifica se a barra de administração está visível no front end
	if ( is_admin_bar_showing() ) {
		$user_color = get_user_option( 'admin_color' );

		// Se houver uma cor, enfileira o esquema de cores para ser usado
		if ( isset( $user_color ) ) {
			$suffix = is_rtl() ? '-rtl' : '';
	    	$suffix .= defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
			wp_enqueue_style( $user_color, admin_url( 'css/colors/' . $user_color . '/colors' . $suffix . ' .css' ) );
		}
	}

}
add_action( 'wp_enqueue_scripts', 'admin_bar_color' );

Transformei essas pequenas linhas em um plugin e chamei de Admin Bar Color. O código está também disponível no GitHub, pra quem quiser contribuir. : )

Categorias
Web

Usando checkboxes para seleção de termos em taxonomias não hierárquicas

Boa dica pros amigos que precisam que suas taxonomias não hierárquicas (ou seja, as que funcionam como tags e usam um campo de texto para preenchimento) funcionem com uma interface um pouco mais amigável.

Basicamente, o código remove a meta box padrão criada pela taxonomia e adiciona a nova através de uma walker class personalizada, uma modificação da Walker_Category_Checklist. Essa classe é necessária para que seja feita a mudança dos valores dos inputs, pois as taxonomias hierárquicas são referenciadas por IDs, enquanto as que não possuem pais nem filhos usam o próprio slug registrado.

Criei um gist também para facilitar a localização do código.

<?php
// Change this to your own taxonomy and post type
new Tag_Checklist( 'taxonomy_name', 'post_type' );
/**
* Use checkbox term selection for non-hierarchical taxonomies
*
* @author Hugh Lashbrooke
* @link http://www.hughlashbrooke.com/wordpress-use-checkbox-term-selection-for-non-hierarchical-taxonomies/
*/
class Tag_Checklist {
private $taxonomy;
private $post_type;
function __construct( $taxonomy, $post_type ) {
$this->taxonomy = $taxonomy;
$this->post_type = $post_type;
// Remove default taxonomy meta box
add_action( 'admin_menu', array( $this, 'remove_meta_box' ) );
// Add new meta box
add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) );
// Handle AJAX call for adding new term
add_action( 'wp_ajax_add-' . $this->taxonomy , '_wp_ajax_add_non_hierarchical_term' );
}
/**
* Remove default meta box
* @return void
*/
public function remove_meta_box() {
remove_meta_box('tagsdiv-' . $this->taxonomy, $this->post_type, 'normal');
}
/**
* Add new metabox
* @return void
*/
public function add_meta_box() {
$tax = get_taxonomy( $this->taxonomy );
add_meta_box( 'taglist-' . $this->taxonomy, $tax->labels->name, array( $this, 'metabox_content' ), $this->post_type, 'side', 'core' );
}
/**
* Generate metabox content
* @param obj $post Post object
* @return void
*/
public function metabox_content( $post ) {
$taxonomy = $this->taxonomy;
$tax = get_taxonomy( $taxonomy );
?>
<div id="taxonomy-<?php echo $taxonomy; ?>" class="categorydiv">
<ul id="<?php echo $taxonomy; ?>-tabs" class="category-tabs">
<li class="tabs"><a href="#<?php echo $taxonomy; ?>-all"><?php echo $tax->labels->all_items; ?></a></li>
<li class="hide-if-no-js"><a href="#<?php echo $taxonomy; ?>-pop"><?php _e( 'Most Used' ); ?></a></li>
</ul>
<div id="<?php echo $taxonomy; ?>-pop" class="tabs-panel" style="display: none;">
<ul id="<?php echo $taxonomy; ?>checklist-pop" class="categorychecklist form-no-clear" >
<?php $popular_ids = wp_popular_terms_checklist( $taxonomy ); ?>
</ul>
</div>
<div id="<?php echo $taxonomy; ?>-all" class="tabs-panel">
<input type="hidden" name="tax_input[<?php echo $taxonomy; ?>][]" value="0" />
<?php
if( class_exists( 'Walker_Tag_Checklist' ) ) {
$walker = new Walker_Tag_Checklist;
}
?>
<ul id="<?php echo $taxonomy; ?>checklist" data-wp-lists="list:<?php echo $taxonomy; ?>" class="categorychecklist form-no-clear">
<?php wp_terms_checklist($post->ID, array( 'taxonomy' => $taxonomy, 'popular_cats' => $popular_ids , 'walker' => $walker ) ) ?>
</ul>
</div>
<?php if ( current_user_can($tax->cap->edit_terms) ) : ?>
<div id="<?php echo $taxonomy; ?>-adder" class="wp-hidden-children">
<h4>
<a id="<?php echo $taxonomy; ?>-add-toggle" href="#<?php echo $taxonomy; ?>-add" class="hide-if-no-js">
<?php
/* translators: %s: add new taxonomy label */
printf( __( '+ %s' ), $tax->labels->add_new_item );
?>
</a>
</h4>
<p id="<?php echo $taxonomy; ?>-add" class="category-add wp-hidden-child">
<label class="screen-reader-text" for="new<?php echo $taxonomy; ?>"><?php echo $tax->labels->add_new_item; ?></label>
<input type="text" name="new<?php echo $taxonomy; ?>" id="new<?php echo $taxonomy; ?>" class="form-required form-input-tip" value="<?php echo esc_attr( $tax->labels->new_item_name ); ?>" aria-required="true"/>
<input type="button" id="<?php echo $taxonomy; ?>-add-submit" data-wp-lists="add:<?php echo $taxonomy ?>checklist:<?php echo $taxonomy ?>-add" class="button category-add-submit" value="<?php echo esc_attr( $tax->labels->add_new_item ); ?>" />
<?php wp_nonce_field( 'add-'.$taxonomy, '_ajax_nonce-add-'.$taxonomy, false ); ?>
<span id="<?php echo $taxonomy; ?>-ajax-response"></span>
</p>
</div>
<?php endif; ?>
</div>
<?php
}
}
if( ! function_exists( '_wp_ajax_add_non_hierarchical_term' ) ) {
/**
* Mod of _wp_ajax_add_hierarchical_term to handle non-hierarchical taxonomies
* @return void
*/
function _wp_ajax_add_non_hierarchical_term() {
$action = $_POST['action'];
$taxonomy = get_taxonomy( substr( $action, 4 ) );
check_ajax_referer( $action, '_ajax_nonce-add-' . $taxonomy->name );
if ( !current_user_can( $taxonomy->cap->edit_terms ) )
wp_die( –1 );
$names = explode( ',', $_POST['new'.$taxonomy->name] );
$parent = 0;
if ( $taxonomy->name == 'category' )
$post_category = isset( $_POST['post_category'] ) ? (array) $_POST['post_category'] : array();
else
$post_category = ( isset( $_POST['tax_input'] ) && isset( $_POST['tax_input'][$taxonomy->name] ) ) ? (array) $_POST['tax_input'][$taxonomy->name] : array();
$checked_categories = array_map( 'absint', (array) $post_category );
foreach ( $names as $tax_name ) {
$tax_name = trim( $tax_name );
$category_nicename = sanitize_title( $tax_name );
if ( '' === $category_nicename )
continue;
if ( ! $cat_id = term_exists( $tax_name, $taxonomy->name, $parent ) )
$cat_id = wp_insert_term( $tax_name, $taxonomy->name, array( 'parent' => $parent ) );
if ( is_wp_error( $cat_id ) )
continue;
else if ( is_array( $cat_id ) )
$cat_id = $cat_id['term_id'];
$checked_categories[] = $cat_id;
if ( $parent ) // Do these all at once in a second
continue;
$new_term = get_term( $cat_id, $taxonomy->name );
$data = "\n<li id='{$taxonomy->name}-{$cat_id}'>" . '<label class="selectit"><input value="' . $new_term->slug . '" type="checkbox" name="tax_input['.$taxonomy->name.'][]" id="in-'.$taxonomy->name.'-' . $new_term->term_id . '"' . checked( in_array( $new_term->term_id, $checked_categories ), true, false ) . ' /> ' . esc_html( apply_filters('the_category', $new_term->name )) . '</label>';
$add = array(
'what' => $taxonomy->name,
'id' => $cat_id,
'data' => str_replace( array("\n", "\t"), '', $data ),
'position' => –1
);
}
$x = new WP_Ajax_Response( $add );
$x->send();
}
}
/**
* Mod of WP's Walker_Category_Checklist class
*/
class Walker_Tag_Checklist extends Walker {
var $tree_type = 'tag';
var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent<ul class='children'>\n";
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
function start_el( &$output, $tax_term, $depth, $args, $id = 0 ) {
extract($args);
if ( empty($taxonomy) )
$taxonomy = 'tag';
if ( $taxonomy == 'tag' )
$name = 'post_tag';
else
$name = 'tax_input['.$taxonomy.']';
$class = in_array( $tax_term->term_id, $popular_cats ) ? ' class="popular-category"' : '';
$output .= "\n<li id='{$taxonomy}-{$tax_term->term_id}'$class>" . '<label class="selectit"><input value="' . $tax_term->slug . '" type="checkbox" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $tax_term->term_id . '"' . checked( in_array( $tax_term->term_id, $selected_cats ), true, false ) . disabled( empty( $args['disabled'] ), false, false ) . ' /> ' . esc_html( apply_filters('the_category', $tax_term->name )) . '</label>';
}
function end_el( &$output, $tax_term, $depth = 0, $args = array() ) {
$output .= "</li>\n";
}
}
?>

Categorias
Web

WordPress readme → GitHub Flavored Markdown

Eis uma ferramenta que converte o arquivo readme.txt padrão do WordPress para o Flavored Markdown do GitHub. Para os afoitos, o código está hospedado para que seja possível o uso imediato.

Aproveitando, há também um plugin para o Sublime Text 2 que faz esse serviço sujo pra você.