A partir de 6 de Dezembro de 2018, a última e maior versão, PHP 7.3 está aqui! Com ele vêm novos recursos úteis, funcionalidades, depreciações, um bom número de correções de bugs e um aumento na performance. O PHP 7.3 também está agora disponível para todos os clientes Kinsta no dashboard do MyKinsta. 🤘

Atualização: PHP 8.1 (versão oficial) está agora disponível para todos os clientes Kinsta. O PHP 7.3 não é mais suportado na Kinsta. Note que somente suportamos versões PHP 8.0, 8.1, 8.2 and 8.3.

Neste post, vamos fornecer uma visão geral das características e mudanças que nós pessoalmente consideramos mais relevantes. Mas você pode sempre verificar a lista completa de recursos, mudanças e correções de erros no PHP 7.3 notas de atualização e no PHP 7.3 Pedidos de Comentários.

O que há de Novo em PHP com PHP 7.3?

Neste post nós estamos cobrindo as seguintes mudanças no PHP 7.3:

Sintaxe Flexível de Heredoc e Nowdoc

Esta é provavelmente uma das melhorias mais relevantes que vem com o PHP 7.3, e nós achamos que ele merece um pouco mais de atenção. Então, antes de mergulhar no PHP 7.3 heredoc/nowdoc mudanças, vamos fornecer uma visão geral rápida deste recurso central útil. Se você já está confiante com o nowdoc e o heredoc, sinta-se livre para saltar para as mudanças do PHP 7.3.

Uma visão geral das sintaxes heredoc e nowdoc

A sintaxe heredoc fornece uma maneira de adicionar uma grande quantidade de texto sem a necessidade de escapar de coisas como aspas duplas. Um heredoc começa com <<< seguido de um marcador, e termina com o mesmo marcador seguido de um ponto-e-vírgula. Aqui está um exemplo:

print <<<EOT
Heredoc text behaves just like a double-quoted string, without the double quotes.
EOT;

Um nowdoc se comporta como um heredoc, com algumas exceções:

  • O identificador está entre aspas simples (<<<<'EOT')
  • Nenhuma análise é feita dentro de um “nowdoc”.

Aqui está um exemplo do nowdoc:

print <<<'EOT'
Nowdocs are to single-quoted strings what heredocs are to double-quoted strings.
EOT;

Heredocs e nowdocs compartilham as mesmas regras que regulam o uso do marcador de fechamento:

  1. O marcador de fecho deve começar na primeira coluna da linha
  2. O marcador deve seguir as mesmas regras de nomenclatura que qualquer outro rótulo em PHP: deve conter apenas caracteres alfanuméricos e sublinhados, e deve começar com um caractere sem dígitos ou sublinhado.

O Manual do PHP avisa:

O Manual do PHP avisa:

É muito importante notar que a linha com o identificador de fechamento não deve conter outros caracteres, exceto um ponto-e-vírgula (;). Isso significa especialmente que o identificador não pode ser recuado, e não pode haver espaços ou abas antes ou depois do ponto-e-vírgula. Também é importante perceber que o primeiro caractere antes do identificador de fechamento deve ser uma nova linha como definida pelo sistema operacional local. Isto é \n sistemas UNIX, incluindo MacOS. O delimitador de fechamento também deve ser seguido por uma nova linha.

Sintaxe inválida do PHP 7.2:

class foo {
    public $bar = <<<EOT
    bar
    EOT;
}
// Identifier must not be indented

Sintaxe válida do PHP 7.2:

class foo {
    public $bar = <<<EOT
bar
EOT;
}

Para mantê-lo curto, no PHP 7.2:

  • O marcador de fecho não pode ser recuado
  • A linha com o marcador de fecho não pode conter caracteres como espaços ou tabulações
  • O primeiro caractere antes do marcador de fecho deve ser uma nova linha
  • O marcador de encerramento deve ser seguido de uma nova linha

É claro o bastante que as sintaxes heredoc e nowdoc são bastante restritivas, mas o PHP 7.3 pode mudar um pouco isso com as seguintes melhorias.

1. Permitir que o marcador de fechamento seja recuado e que o espaço em branco principal seja removido

Com o PHP 7.3 temos permissão para recuar o marcador de fechamento, e podemos escrever com segurança o seguinte código:

class foo {
    public $bar = <<<EOT
        bar
    EOT;
}

A indentação do marcador de fechamento define a quantidade de espaços em branco (ou abas) que serão retirados de cada linha do corpo. Mas tenha cuidado: o marcador de fechamento nunca deve ser recuado mais do que qualquer outra linha do corpo.

Veja o código abaixo:

class foo {
    public $bar = <<<EOT
    bar
        EOT;
}

O código acima emitiria o seguinte erro de análise:

Parse error: Invalid body indentation level (expecting an indentation at least ...) in %s on line %d

Descascando abas e espaços em branco nos permitem indentar o corpo do heredoc/nowdoc para o mesmo nível do código ao redor, e sem espaços em branco desnecessários antes de cada linha do corpo.

Podemos usar ambas as abas e espaços para indentação, mas não temos permissão para usá-los intermixados. Isto significa que devemos usar os mesmos caracteres de indentação para o marcador de fechamento e quaisquer linhas do corpo. No caso de caracteres de indentação diferentes, esperaríamos um tipo diferente de erro de análise (indentação inválida).

2. Remover o requisito da Trailing New Line do marcador de fechamento

Atualmente, uma nova linha deve seguir o marcador para encerrar a heredoc/nowdoc. O PHP 7.3 mudaria isso e nos permitiria terminar o heredoc/nowdoc na mesma linha. Aqui está um exemplo da RFC:

Sintaxe válida do PHP 7.2:

$values = [<<<END
a
b
c
END
, 'd e f'];

Sintaxe válida do PHP 7.3:

$values = [<<<END
a
b
c
END, 'd e f'];

Seja como for, tenha cuidado ao escolher o nome do seu marcador porque “ocasionalmente” você pode esperar um erro se ele corresponder a uma palavra que você usou no corpo do heredoc/nowdoc (leia mais sobre isso no RFC e no GitHub).

Ambas as propostas foram aprovadas com mais de 2/3 dos votos.

PHP 7.3 RFC

Recursos adicionais

Permitir uma vírgula em chamadas de função

Trailing commas (ou “vírgulas finais”) são vírgulas anexadas a uma lista de elementos, parâmetros ou propriedades e são úteis em contextos onde novos valores são acrescentados frequentemente porque evitam erros devido à falta de uma vírgula. No PHP são permitidas vírgulas trailing em arrays, e a partir do PHP 7.2 são permitidas em namespaces agrupados.

A partir do PHP 7.3, vírgulas a seguir seriam permitidas nas declarações de função. As funções variadas

foo(
    $bar,
    $baz,
);

Podemos usar uma vírgula trailing quando estamos criando um array com compact(), para retornar uma string formatada com sprintf(), ou ao fundir um array:

$newArray = array_merge(
    $arrayOne,
    $arrayTwo,
    ['foo', 'bar'],
);

Além disso, vírgulas a seguir seriam úteis para depuração:

var_dump(
    $foo,
    $bar,
    $baz,
);

E eles são poderosos com unset() e isset():

unset(
    $foo,
    $bar,
    $baz,
);

isset(
    $foo,
    $bar,
    $baz,
);

Várias vírgulas serão permitidas em chamadas de método e anexos, também.

Nota: Esta alteração afectaria apenas as chamadas de função. A sintaxe da declaração de função não será alterada. Além disso, não serão permitidas vírgulas isoladas, vírgulas múltiplas e vírgulas principais.

Exemplos adicionais podem ser encontrados na página RFC. Este RFC passou com 30 a 10 votos.

PHP 7.3 RFC

JSON_THROW_ON_ERROR

Uma das funcionalidades mais apreciadas com o PHP 7.3 fornece uma nova maneira de lidar com erros JSON. Esta não é uma característica central, mas uma adição à extensão JSON que mudaria o comportamento de erro de json_decode() e json_encode().

Atualmente, json_decode() retorna null on error, mas null também pode ser um resultado válido. Isto pode ser confuso, porque

Só é possível saber se um erro ocorreu chamando json_last_error() ou json_last_error_msg(), que retornam o estado de erro global em formulários legíveis por máquina e legíveis por humanos respectivamente. – PHP RFC

json_encode() retorna FALSE no erro. Isto é mais claro porque existe um valor de erro específico. De qualquer maneira, ambas as funções não interrompem a execução do programa por erro, nem lançam nenhum aviso.

Com isso dito, aqui está a proposta para o PHP 7.3:

Esta RFC propõe adicionar um novo valor de sinalizador de opção para json_decode() e json_encode(), JSON_THROW_ON_ERROR. Quando este flag é ultrapassado, o comportamento de erro destas funções é alterado. O estado de erro global é deixado intocado, e se ocorrer um erro que de outra forma o definiria, essas funções em vez disso lançam uma JsonException com a mensagem e código definidos para qualquer json_last_error() e json_last_error_msg() seria respectivamente.

Aqui está um exemplo mostrando uma maneira simples de lançar um erro JSON:

try {
    json_decode("{", false, 512, JSON_THROW_ON_ERROR);
}
catch (\JsonException $exception) {
    echo $exception->getMessage(); // echoes "Syntax error"
}

Lançar uma exceção após o erro daria várias vantagens que você encontrará listadas na RFC.

Nota: um parâmetro de profundidade inválido passado para json_decode() produz um aviso e retorna NULL. Este comportamento não será afetado pelo JSON_THROW_ON_ON_ERROR. Da mesma forma, os erros de análise de parâmetros não são afetados por JSON_THROW_ON_ERROR e continuam a produzir avisos.

Esta proposta foi aprovada com 23 votos a favor e 0 contra.

PHP 7.3 RFC

Additional Resources

list() Atribuição de referência

O que Significa Atribuição de Referência?

Considere a seguinte linha:

$b = &$a;

Aqui $b recebe o valor de $a, mas esse valor não é copiado de $a para $b. No PHP podemos atribuir um valor por referência, o que significa que duas variáveis podem apontar para os mesmos dados, e cada mudança em qualquer variável afeta os dados originais. Aqui está um exemplo do manual do PHP:

<?php
$a = 3;
$b = &$a; // $b is a reference to $a

print "$a\n"; // prints 3
print "$b\n"; // prints 3

Agora, vamos mudar o valor de $a:

$a = 4; // change $a

print "$a\n"; // prints 4
print "$b\n"; // prints 4 as well, since $b is a reference to $a, which has been changed

Qual é a Lista () Construir e Como ele Muda com o PHP 7.3

A construção da linguagem list() pode ser usada para “atribuir variáveis como se elas estivessem em um array”, mas com list() não temos permissão para atribuir valores de variáveis por referência.

O PHP 7.3 deve mudar isso permitindo-nos atribuir variáveis por referência também com a construção list(), como mostrado no seguinte exemplo:

$array = [1, 2];
list($a, &$b) = $array;

Que é o mesmo que:

$array = [1, 2];
$a = $array[0];
$b =& $array[1];

A vantagem desta proposta é que poderíamos agora atribuir múltiplas variáveis por referência, o que atualmente não era permitido. Mais exemplos estão disponíveis na RFC. Esta proposta foi aprovada com 17 votos a favor e 7 contra.

PHP 7.3 RFC

Recursos adicionais

Função is_countable

Outro recurso útil que vem com o PHP 7.3 é a função is_countable(). Até o PHP 7.2, obtemos um erro ao tentar contar() algo que não é contável. Por esta razão, a fim de evitar um aviso, somos forçados a adicionar o seguinte código:

if (is_array($foo) || $foo instanceof Countable) {
    // $foo is countable
}

Esta RFC propõe a função is_countable(), que retorna true se a variável dada for um array ou uma variável contável, false otherwise. Assim, o código acima pode ser alterado da seguinte forma:

if (is_countable($foo)) {
    // $foo is countable
}

Esta proposta foi aprovada com 25 votos a favor e 0 contra.

PHP 7.3 RFC

Recursos adicionais

array_key_first(), array_key_last()

Atualmente, podemos recuperar a primeira e a última chave de um array usando as funções reset(), end(), end() e key(). Infelizmente, com essas funções, não há como reunir o primeiro ou o último índice de um array sem alterar seu estado interno. Outras opções normalmente reduzem a legibilidade e o desempenho do código.
Esta proposta mudaria este cenário adicionando duas novas funções ao núcleo do PHP:

  • array_key_first()
  • array_key_last()

A partir do PHP 7.3, array_key_first() e array_key_last() permitem recuperar a primeira e última chave de um dado array sem afetar o ponteiro interno do array. Essas novas funções nos permitiriam escrever códigos menos complexos e, em alguns casos, evitar erros. Consultar a RFC para obter mais informações e vários exemplos.

array_key_first() e array_key_last() foram aprovados com 18 a 14 votos.

Nota: a RFC original propôs mais duas funções, array_value_first() e array_value_last(), que foram votadas em uma pesquisa diferente, mas não foram aprovadas e não se tornarão parte do núcleo do PHP.

PHP 7.3 RFC

Recursos adicionais

Argon2 Password Hash Enhancements

Argon2 é um algoritmo de hashing implementado no PHP 7.2 como uma alternativa ao algoritmo Bcrypt. O PHP 7.2 introduziu a constante PASSWORD_ARGON2I, disponível para ser usada em funções password_*:

password_hash('password', PASSWORD_ARGON2I);

Desde sua primeira implementação, uma nova variante do Argon2 foi adicionada, então, no momento em que este artigo foi escrito, o Argon2 vem em três variantes:

  • Argon2d maximiza a resistência a ataques de quebra de GPU. É mais rápido e utiliza o acesso à memória dependente de dados.
  • Argon2i usa acesso à memória independente de dados, que é preferido para o hashing de senha. É mais lento porque faz mais passagens sobre a memória para proteger de ataques de tradeoff.
  • Argon2id é uma versão híbrida que combina a abordagem Argon2i para a primeira passagem sobre a memória, e a abordagem Argon2d para passagens subsequentes.

Argon2id é recomendado na Internet, exceto quando há boas razões para preferir especificamente outra variante.

A nova RFC propõe a implementação do Argon2id dentro das funções password_* com a nova constante PASSWORD_ARGON2ID:

password_hash('password', PASSWORD_ARGON2ID);

A implementação é idêntica à implementação do Argon2i, e aceitará os mesmos fatores de custo:

  • Um custo de memória que define o número de KiB que devem ser consumidos durante o hashing (os valores padrão são 1<10, ou 1024 KiB, ou 1 MiB)
  • Um custo de tempo que define o número de iterações do algoritmo de hashing (padrão 2)
  • Um fator de paralelismo, que define o número de roscas paralelas que serão usadas durante o hashing (o padrão é 2)

Veja o seguinte código:

$options = ['memory_cost' => 1<<11, 'time_cost' => 4, 'threads' => 2];
password_hash('password', PASSWORD_ARGON2ID, $options);

Mais informações e exemplos sobre a RFC.

PHP 7.3 RFC

Recursos adicionais

Depreciações

As seguintes funções/funcionalidades serão depreciadas com o PHP 7.3 e removidas não depois do PHP 8.0.

Depreciar e remover image2wbmp()

A função image2wbmp() produz ou salva uma versão WBMP de uma determinada imagem. Esta função tem três argumentos: um recurso de imagem, um nome de arquivo (o caminho para o arquivo salvo) e uma cor de primeiro plano.
A partir do PHP 5.0, ele é idêntico ao imagewbmp(), então esta RFC propõe depreciá-lo e removê-lo.
Desde o PHP 7.3, cada chamada para image2wbmp() emitiria um aviso de depreciação. Após a remoção, cada chamada provocaria um erro fatal.

PHP 7.3 RFC

Depreciar e Remover Constantes não Sensíveis a Maiúsculas e Minúsculas

O PHP atualmente suporta constantes sensíveis e não sensíveis a maiúsculas e minúsculas. De qualquer forma, constantes não sensíveis a maiúsculas e minúsculas são suportadas, mas consideradas sujeitas a inconsistências em funcionalidades e complexas de usar.
Esta proposta começa com as seguintes premissas:

  • as constantes de classe são sempre sensíveis a maiúsculas e minúsculas
  • constantes globais declaradas com const são sempre case-sensitive
  • constantes definidas com define() são case-sensitive por padrão

Além disso, a Referência à Linguagem PHP afirma explicitamente:

Uma constante é sensível a maiúsculas e minúsculas por padrão. Por convenção, os identificadores de constantes são sempre em maiúsculas.

Dito isto, esta RFC propõe as seguintes alterações:

  • Deprecate chamando define() com o terceiro parâmetro definido como true – PHP 7.3
  • Depreciar o acesso a constantes não sensíveis a maiúsculas e minúsculas com um invólucro diferente da declaração (com exceção de true, false e null) – PHP 7.3
  • Remova a possibilidade de declarar constantes não sensíveis a maiúsculas e minúsculas – PHP 8.0
  • Converta verdadeiro, falso e nulo de constantes em caixa especial em palavras-chave reservadas – PHP 8.0

PHP 7.3 RFC

Depreciar e remover constantes não sensíveis a maiúsculas e minúsculas.

Depreciações Adicionais para PHP 7.3

Aqui está uma lista rápida de funcionalidades sendo depreciadas no PHP 7.3. Não é exaustivo, são apenas as propostas de depreciação que eu pessoalmente considero mais relevantes. Para uma lista completa das depreciações propostas, veja Depreciações para PHP 7.3.

Apelidos de funções mbstring indocumentados: há um número de apelidos de funções mbstring indocumentados que são duplicações de funções equivalentes usando prefixo mb_. Por exemplo, mbereg é um alias de mb_ereg.
Todas essas funções seriam marcadas como depreciadas e um aviso de depreciação seria lançado quando elas fossem encontradas durante a compilação.

Funções de busca por corda com agulha inteira: estas funções operam normalmente com agulhas de corda. Se uma agulha sem cordas é dada, ela é convertida para um inteiro e aplicada como o valor ordinal de um caractere (leia mais no manual do PHP). Aqui está um exemplo da RFC:

$str = "There are 10 apples";
var_dump(strpos($str, "10")); // int(10)
var_dump(strpos($str, 10));   // bool(false)

Isso é considerado confuso e causa problemas imprevisíveis porque o tipo pode mudar com a fonte de dados do usuário. Por esse motivo, a RFC propõe a emissão de um aviso de depreciação se uma agulha sem cordas for passada para uma das seguintes funções:

  • strpos
  • strrpos
  • stripos
  • strripos
  • strstr
  • strchr
  • strrchr
  • stristr

No PHP 8.0, o aviso de depreciação deve ser removido e as agulhas devem ser automaticamente convertidas em strings.

fgetss() function e string.strip_tags stream filter: fgetss() e string.strip_tags strip tags de um stream enquanto o lêem. Tanto a função quanto o filtro expõem a funcionalidade strip_tags() tornando a implementação de strip_tags() mais complexa, já que uma máquina de estado de streaming é necessária. Além disso, a RFC aponta outra desvantagem dessas funções:

Por outro lado, essas funções parecem ser de muito pouca utilidade. strip_tags() itself, devido às suas limitações e bugs conhecidos, já tem muito poucas aplicações legítimas. Não há necessidade de fornecer suporte nativo para aplicativos de streaming além disso.

Então a RFC propõe marcar fgetss(), gzgetss() e SplFileObject::fgetss() como depreciados.

O que o PHP 7.3 Significa para Usuários do WordPress?

De acordo com a página oficial de Estatísticas do WordPress, a partir de agora, apenas 32,9% dos usuários do WordPress atualizaram para PHP 7 ou superior. Apenas 4% estão usando PHP 7.2. Você pode ver que a grande maioria dos usuários, mais de 38%, ainda estão rodando no PHP 5.6. O que é ainda mais assustador é que mais de 28,5% dos usuários estão usando versões PHP não suportadas. Em Dezembro de 2016, o WordPress.org aumentou sua recomendação oficial para usuários de PHP 5.6 para PHP 7 ou superior.

Versões do WordPress PHP
Versões do WordPress PHP

Desempenho do PHP 7

Os números acima são especialmente desencorajadores vindo de um ponto de vista de desempenho, já que o PHP 7 mostrou ser significativamente mais rápido. Aqui estão algumas estatísticas:

  • Benchmarks oficiais do PHP mostram que o PHP 7 permite que o sistema execute duas vezes mais solicitações por segundo em comparação com o PHP 5.6, em quase metade da latência.
  • Christian Vigh também publicou uma comparação de performance PHP na qual ele descobriu que o PHP 5.2 era 400% mais lento que o PHP 7.

Fizemos os nossos próprios benchmarks de desempenho PHP. E similarmente aos benchmarks acima, vimos que o WordPress 5.0 no PHP 7.3 poderia executar quase três vezes mais transações (pedidos) por segundo em comparação com o PHP 5.6.

Referências do WordPress 5.0 PHP
Referências do WordPress 5.0 PHP
  • WordPress 5.0 PHP 5.6 benchmark: 91,64 req/sec
  • Resultados de benchmark do WordPress 5.0 PHP 7.0: 206.71 req/sec
  • Resultados de benchmark do WordPress 5.0 PHP 7.1: 210.98 req/sec
  • Resultados de benchmark do WordPress 5.0 PHP 7.2: 229.18 req/sec
  • WordPress 5.0 PHP 7.3 resultados de benchmark: 253.20 req/sec 🏆

Também é interessante notar que o WordPress 4.9.8 no PHP 7.3 foi ligeiramente mais rápido que o WordPress 5.0.

Referências do WordPress 4.9.8 PHP
Referências do WordPress 4.9.8 PHP
  • WordPress 4.9.8 PHP 5.6 benchmark: 97,59 req/sec
  • Resultados de benchmark do WordPress 4.9.8 PHP 7.0: 221.42 req/sec
  • WordPress 4.9.8 PHP 7.1 resultados de benchmark: 233.78 req/sec
  • WordPress 4.9.8 PHP 7.2 resultados de benchmark: 250.36 req/sec
  • WordPress 4.9.8 PHP 7.3 resultados de benchmark: 276.31 req/sec 🏆

Muitos são lentos para atualizar simplesmente por causa do tempo envolvido com o teste de novos todos os seus plugins de terceiros e temas para garantir que eles funcionam corretamente. Mas muitas vezes, resume-se ao fato de ainda não o terem feito.

Verificando sua Versão PHP

Não tem certeza de qual versão do PHP você está executando? Uma das maneiras mais fáceis de verificar é usar uma ferramenta como o Pingdom ou o Google Chrome Devtools. O primeiro cabeçalho do pedido HTTP mostrará tipicamente a versão.

Verificar versão do PHP
Verificar versão do PHP

Isso depende da máquina não modificar o valor do cabeçalho X-Powered-By. Se o fizerem, você pode não ver sua versão do PHP. Nesse caso, você também pode instalar um plugin gratuito, como Version Info, que mostrará algumas informações básicas do servidor no rodapé do seu painel de administração do WordPress.

Verifique a versão PHP no WordPress
Verifique a versão PHP no WordPress

Alternativamente, você também pode fazer upload de um arquivo via FTP para ver sua versão do PHP, ou alcançar sua máquina e perguntar.

Atualizando para PHP 7.3

A versão final do PHP 7.3 está aqui e você pode começar a testá-lo imediatamente. Você pode testar seu site WordPress localmente ou verificar seus scripts em um ambiente como o Docker, que permite que você teste diferentes versões do PHP a partir da linha de comando.

Ou você pode utilizar um ambiente de encenação, pois isso se assemelhará mais de perto a um local de produção ao vivo. Crie um ambiente de testes com alguns cliques simples no painel do MyKinsta.

Ambiente de preparação do WordPress
Ambiente de preparação do WordPress

Recomendamos sempre a realização de testes minuciosos antes de utilizá-lo em um local de produção. Para fazer isso, basta alterar o mecanismo PHP para o site de preparação em “Ferramentas” e você pode começar a testar para garantir a compatibilidade de seus plugins e temas de terceiros.

Alterar para PHP 7.3
Alterar para PHP 7.3

Depois de confirmar que tudo funciona, você pode mudar o seu site de produção para PHP 7.3 ou se você fez alguma alteração, também empurre seu site de testes para o ar.

Resumo

A última e maior versão do PHP está aqui. Ele nos traz brindes como heredocs e nowdocs flexíveis, vírgulas trailing em chamadas de funções, list() atribuições de referência e mais. Neste post, fornecemos uma visão geral de nossas melhorias e mudanças favoritas, mas também gostaríamos de saber quais são as suas favoritas e de que forma você as aproveitará. Deixe-nos saber nos comentários abaixo. E não se esqueça que PHP não está morto!

Você pode encontrar a lista completa de propostas do PHP 7.3 na página Requests For Comments e nas Notas de Atualização do PHP 7.3 do GitHub.

Carlo Daniele Kinsta

Carlo is a passionate lover of webdesign and front-end development. He has been playing with WordPress for more than 20 years, also in collaboration with Italian and European universities and educational institutions. He has written hundreds of articles and guides about WordPress, published both on Italian and international websites, as well as on printed magazines. You can find him on LinkedIn.