Wordpress Avançado

Ordenar posts por meta_value_num: o preço em ordem certa no WP_Query

A vitrine ordenada por preço mostra 1200 logo antes de 89, e não é bug do tema. O valor mora na wp_postmeta, cuja coluna meta_value é longtext, e texto ordena caractere por caractere: “1200” vem antes de “89” pelo mesmo motivo que “ab” vem antes de “b”. A correção é uma palavra: troque meta_value por meta_value_num no orderby.

A consulta que ordena certo

<?php
$q = new WP_Query( [
    'post_type'      => 'produto',
    'posts_per_page' => 12,
    'meta_key'       => 'preco',
    'orderby'        => 'meta_value_num',
    'order'          => 'ASC',
] );

O meta_key é obrigatório aqui, senão o WordPress não sabe qual linha da postmeta juntar. Por baixo, o WP_Query 6.9 monta o ORDER BY como meta_value+0, o que joga a string para número no próprio MySQL 8. Efeito colateral: esse meta_key gera um INNER JOIN, então produto sem o campo preco some da lista.

Trazendo quem não tem o campo

<?php
$q = new WP_Query( [
    'post_type'      => 'produto',
    'posts_per_page' => 12,
    'meta_query'     => [
        'relation'  => 'OR',
        'com_preco' => [
            'key'     => 'preco',
            'type'    => 'DECIMAL(10,2)',
            'compare' => 'EXISTS',
        ],
        'sem_preco' => [
            'key'     => 'preco',
            'compare' => 'NOT EXISTS',
        ],
    ],
    'orderby'        => [ 'com_preco' => 'ASC' ],
] );

Dando nome à cláusula, o orderby aceita esse nome direto. E aqui mora a pegadinha que me pegou: ordenando por cláusula nomeada, o WordPress usa CAST(meta_value AS ...) com o type que você declarou — e NUMERIC vira SIGNED lá dentro, que corta os centavos. Com preço, peça DECIMAL(10,2); o 19,90 e o 19,99 dependem disso.

Quem cai no ramo NOT EXISTS entra com valor nulo e, em ASC, o MySQL 8 coloca nulo na frente de tudo. Se esses tiverem que ficar no fim da vitrine, ordene DESC ou grave zero no campo na hora de salvar o produto. E confira o valor cru na tabela antes de caçar plugin: campo gravado com R$ na frente ou vírgula no lugar do ponto continua saindo torto, porque a conversão para no primeiro caractere que não é número.

Post Recentes

cron_schedules WordPress: intervalo de 5 minutos no WP-Cron

O WordPress só oferece hourly, twicedaily, daily e weekly. Use o filtro cron_schedules para criar um intervalo de 5 minutos…

17 horas atrás

E-mails do WooCommerce não chegam: como testar o envio de um pedido real

Dispare pela linha de comando o e-mail de um pedido que já existe na loja e descubra se a falha…

24 horas atrás

CodeIgniter 4 tela branca: CI_ENVIRONMENT e o erro que sumiu

Página em branco no CodeIgniter 4, sem nenhuma mensagem? O ambiente está em production e escondeu o erro. Troque o…

2 dias atrás

Google Consent Mode v2 no WordPress: default denied antes do gtag rodar

O Google Ads acusa consentimento ausente porque o gtag sobe antes do banner. Veja como injetar o default denied do…

3 dias atrás

Módulos PHP 8.3 faltando na Saúde do site do WordPress: como instalar

A tela Saúde do site avisa que faltam extensões como intl, imagick ou zip: instale no PHP 8.3, reinicie o…

3 dias atrás

Caso de teste PHPUnit a partir do bug: do relato solto para o teste que falha

Chegou um chamado sem passo a passo e sem exemplo. Veja como virar esse relato em um caso de teste…

4 dias atrás