Widgets do WordPress: Começando com Padrões
O objetivo desta série é começar a mergulhar mais fundo no trabalho com programação orientada a objetos no contexto do WordPress.
E como a API do WordPress Widgets é uma das APIs que usa práticas orientadas a objetos, é um lugar lógico para começar. Além disso, ele nos dará algumas técnicas fundamentais que podemos usar para aplicar em trabalhos futuros, pois veremos como construir mais projetos orientados a objetos no WordPress em séries futuras.
Até agora, cobrimos o seguinte:
- Widgets do WordPress: uma abordagem orientada a objetos. A API Widgets fornece um teste decisivo sólido e um exemplo de como começar a programação orientada a objetos no WordPress.
- Widgets do WordPress: Como detectar programação orientada a objetos. O objetivo é armar você com tudo que você precisa para detectar práticas orientadas a objetos.
Se você não está preso, agora é um ótimo momento para fazê-lo. E se você tiver, então você vai se lembrar do último post, terminamos com a seguinte nota:
Ou seja, vamos revisitar o WordPress Widget Boilerplate e vou refatorá-lo em seu estado atual para adotar padrões PHP mais modernos.
Para começar a atualizar o WordPress Widget Boilerplate para seguir esses padrões, precisamos fazer algumas coisas:
- crie uma ramificação a partir do clichê existente,
- instalar ferramentas de qualidade de código,
- garantir que nosso IDE esteja configurado corretamente,
- e comece a refatorar o código para esses padrões.
E é isso que vamos começar a fazer com este post.
Começando com padrões
Se você é membro deste site há algum tempo, sabe que prefiro usar o Visual Studio Code. Se não, eu tenho um conjunto inteiro de artigos dedicados a como eu o uso (e, portanto, como o usaremos ao longo desta série de posts).
E se você estiver interessado em cobertura sobre padrões de codificação, depuração, IDEs, ambientes de desenvolvimento e assim por diante, confira The Independent WordPress Developer.
No entanto, estou assumindo que se você está lendo isso, então você leu todo o material acima ou está confortável lendo todo o material acima.
Dito isso, vamos começar.
Baixando o Repositório
A primeira coisa que você vai querer fazer é clonar uma cópia do repositório. Eu prefiro fazer isso através da linha de comando.
Além disso, também acho que vale a pena fazer isso contra a versão mais recente do WordPress. Se você não tem uma cópia do tronco do WordPress do Subversion, você pode ler como configurar isso aqui; no entanto, isso é puramente opcional. Você pode acompanhar o restante deste tutorial com qualquer versão do WordPress que desejar.
Para fazê-lo,
- Verifique se você está no diretório de plugins da sua instalação do WordPress
- E, em seguida, digite os seguintes comandos em uma cópia do seu terminal
$
Isso criará um diretório WordPress-Widget-Boilerplate em seu diretório de plugins. Você pode navegar até ele digitando simples:
$ cd WordPress-Widget-Boilerplate
Os resultados da clonagem do repositório devem ser parecidos com isto:
Em seguida, você precisa ter certeza de mudar para o branch de desenvolvimento que eu criei. É muito fácil fazer isso. Mas antes de fazermos isso, por que não configurar o projeto no Visual Studio?
Configurando o código do Visual Studio
As etapas para configurar o projeto no Visual Studio Code são simples:
- Arraste o diretório do Boilerplate para o IDE,
- Abra o terminal integrado,
- Trocar filiais
Assim como fiz acima, fornecerei um screencast sobre como fazer tudo isso. Arrastar um diretório para o Visual Studio Code deve ser bastante fácil, mas trocar ramificações na linha de comando pode ser um pouco diferente.
Primeiro, configurando o projeto no Visual Studio Code:
Observe aqui que também abro o terminal integrado pressionando o atalho CMD + P (estou no macOS, portanto, seu atalho pode ser diferente). Então eu insiro o comando para verificar a ramificação de desenvolvimento .
Depois de fazer isso, seu repositório local deve mudar para o branch de desenvolvimento. Você pode confirmar que é o branch do qual você está trabalhando digitando:
$ git branch
E, em seguida, revise o conteúdo do terminal. A rigor, o desenvolvimento deve ser destacado.
Neste ponto, vamos introduzir alguns novos arquivos no projeto. No final deste tutorial, você pode formar um pull para obter tudo o que estou prestes a documentar aqui. Mas como o objetivo do que estamos fazendo é duplo, é importante ter certeza de que estamos fazendo isso na sequência correta, porque o primeiro passo é algo que eu uso em todos os projetos para WordPress neste momento.
Então, com isso dito, vamos dar uma olhada.
Compositor e qualidade do código
A primeira coisa que gosto de fazer é configurar uma série de ferramentas para reforçar a qualidade do código. Isso é alcançado por uma variedade de pacotes do Composer. Esses incluem:
- GrumPHP. Uma ferramenta de qualidade de código PHP. Não subestime o esclarecimento e o grau em que este repositório está cheio de informações. Se você ficar preso a qualquer uma das outras ferramentas mencionadas aqui, consulte primeiro a documentação deste repositório.
- Fixador PHP CS. Uma ferramenta para corrigir automaticamente problemas de padrões de codificação PHP.
- PHP Paralelo Lint. Esta ferramenta verifica a sintaxe de arquivos PHP mais rápido do que a verificação serial com uma saída mais sofisticada.
- PHPMD. Este utilitário pega uma determinada base de código fonte PHP e procura vários problemas potenciais dentro dessa fonte
- Analisador PHP. Um analisador é útil para análise estática, manipulação de código e, basicamente, qualquer outro aplicativo que lide com código programaticamente.
- Gerenciador de proxy. Esta biblioteca tem como objetivo fornecer uma abstração para geração de vários tipos de classes proxy.
Quero deixar duas coisas claras:
- As ferramentas acima são o mínimo que eu uso, e você provavelmente me verá usando ferramentas adicionais no futuro,
- as ferramentas acima ajudarão a impor regras de qualidade de código antes de verificar o código em um repositório. Destina-se a complementar a configuração em seu IDE.
Para configurar e executar essas ferramentas no projeto, precisaremos criar um arquivo composer.json parecido com este :
{
"name": "wordpress-widget-boilerplate/wordpress-widget-boilerplate",
"description": "An organized, maintainable boilerplate for building widgets using WordPress best practices.",
"type": "wordpress-plugin",
"license": "GPL-3.0-or-later",
"homepage": "https://github.com/tommcfarlin/WordPress-Widget-Boilerplate",
"authors": [
{
"name": "Tom McFarlin",
"email": "tom@pressware.co",
"homepage": "https://pressware.co"
}
],
"support": {
"issues": "https://github.com/tommcfarlin/WordPress-Widget-Boilerplate/issues"
},
"config": {
"preferred-install": "dist",
"platform": {
"php": "7.1"
}
},
"repositories": [
{
"type": "composer",
"url": "https://wpackagist.org"
}
],
"require": {
"php": "7.1",
"composer/installers": "^1.4"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^2.13.1",
"jakub-onderka/php-parallel-lint": "^1.0.0",
"phpmd/phpmd": "^v2.6.0",
"nikic/php-parser": "^4.0",
"ocramius/proxy-manager": "^2.0.0",
"phpro/grumphp": "^0.13.1"
},
"scripts": {
"test": [
"./vendor/bin/grumphp run"
]
},
"minimum-stability": "stable"
}
Lembre-se, você pode puxar isso manualmente no final deste post. Se, no entanto, você quiser acompanhar, sinta-se à vontade para fazer isso manualmente. Eu nunca iria querer desencorajá-lo disso. 🙂
Depois de criar o arquivo composer.json, certifique-se de executar o seguinte comando no terminal:
$ composer install
Isto pode tomar algum tempo; no entanto, uma vez feito, você deve receber a seguinte mensagem:
Atenção! GrumPHP está farejando seus commits!
Para fazer uma simulação, digite o seguinte comando no seu terminal:
$ vendor/bin/grumphp run
Dependendo de como você está trabalhando com o projeto, você pode ver uma saída parecida com esta:
Mas há mais trabalho a fazer. Ou seja, precisamos:
- atualize nosso arquivo .gitignore ,
- introduzir configuração para GrumPHP
- introduzir configuração para PHPMD,
- introduzir configuração para PHPCS,
- eventualmente, reestruture a estrutura de diretórios do clichê.
Tudo até a etapa final, vamos tentar fazer neste post.
Atualizando o arquivo Ignorar
Primeiro, não queremos confirmar o diretório do fornecedor ou o arquivo de bloqueio do compositor. Eles podem ser gerados sempre que um usuário baixa o diretório. Eles podem facilmente ficar fora de sincronia e adicionar um tamanho enorme ao diretório do projeto.
Para esse fim, seu arquivo gitignore deve ficar assim :
*.DS_Store
*.log
wp-config.php
wp-content/advanced-cache.php
wp-content/backup-db/
wp-content/backups/
wp-content/blogs.dir/
wp-content/cache/
wp-content/upgrade/
wp-content/uploads/
wp-content/mu-plugins/
wp-content/wp-cache-config.php
wp-content/plugins/hello.php
/.htaccess
/license.txt
/readme.html
/sitemap.xml
/sitemap.xml.gz
vendor/
composer.lock
Isso diz ao plugin para ignorar qualquer coisa, exceto o que está na raiz do diretório do plugin (e alguns dos eventuais diretórios que criaremos) junto com alguns arquivos básicos que estamos acostumados a ver nas instalações do WordPress.
Algumas das coisas que você vê, como wp-config.php ou wp-content/backups, você provavelmente nunca verá no contexto de um plugin, mas essas são diretivas padrão para ignorar o WordPress que eu gosto de manter à mão.
Você notará que também adicionei o arquivo de bloqueio do fornecedor e do compositor na parte inferior do arquivo.
Configurar GrumPHP
GrumPHP pode fazer muito, e se você gastou algum tempo examinando o repositório antes de ler até aqui, então você provavelmente sabe disso; no entanto, vou mantê-lo o mais enxuto possível, para que ele forneça as instruções necessárias para as ferramentas que estamos usando e nada mais.
parameters:
git_dir: .git
bin_dir: vendor/bin
process_timeout: 120
tasks:
securitychecker:
composer:
jsonlint:
xmllint:
yamllint:
phplint:
exclude:
- vendor/
phpcs:
metadata:
priority: 200
phpcsfixer2:
allow_risky: true
config: '.php_cs.dist'
metadata:
priority: 300
phpparser:
visitors:
forbidden_function_calls:
blacklist:
- "exit"
- "var_dump"
phpversion:
project: '7.1'
phpmd:
exclude: ['vendor']
ruleset: ['phpmd.xml']
Em suma, isso diz para executar uma variedade de verificações para:
- segurança,
- compositor,
- JSON,
- XML,
- Yaml,
- PHP,
- PHPCS,
- Analisador PHP,
- PHPMD,
- e mais.
Assim que terminarmos de configurar todo o resto, mostrarei como tudo isso se encaixa. Mas primeiro, vamos terminar de configurar o restante de nossos utilitários.
PHPCS
Isso usa dois arquivos separados – um arquivo dist e um arquivo XML – cada um dos quais serve a propósitos diferentes, embora muito úteis.
O primeiro arquivo, php_cs.dist, que você verá no repositório no final deste post, fornece um cabeçalho que é aplicado a todos os arquivos PHP em nosso projeto. Ele também impõe algumas regras diferentes que melhoram a qualidade do código.
As regras são auto-explicativas e você pode ver o que será aplicado simplesmente examinando cada uma das regras definidas.
<?php
$header = <<<'EOF'
This file is part of the WordPress Widget Boilerplate
(c) Tom McFarlin <tom@tommcfarlin.com>
This source file is subject to the GPL license that is bundled
with this source code in the file LICENSE.
EOF;
return PhpCsFixerConfig::create()
->setRiskyAllowed(true)
->setRules([
'@PHP56Migration' => true,
'@Symfony' => true,
'@Symfony:risky' => true,
'align_multiline_comment' => true,
'array_syntax' => ['syntax' => 'short'],
'blank_line_before_statement' => true,
'combine_consecutive_issets' => true,
'combine_consecutive_unsets' => true,
// one should use PHPUnit methods to set up expected exception instead of annotations
'general_phpdoc_annotation_remove' => ['annotations' => ['expectedException', 'expectedExceptionMessage', 'expectedExceptionMessageRegExp']],
'header_comment' => ['header' => $header],
'heredoc_to_nowdoc' => true,
'list_syntax' => ['syntax' => 'long'],
'method_argument_space' => ['ensure_fully_multiline' => true],
'method_chaining_indentation' => false,
'no_extra_consecutive_blank_lines' => ['tokens' => ['break', 'continue', 'extra', 'return', 'throw', 'use', 'parenthesis_brace_block', 'square_brace_block', 'curly_brace_block']],
'no_null_property_initialization' => true,
'no_short_echo_tag' => true,
'no_unneeded_curly_braces' => true,
'no_unneeded_final_method' => true,
'no_unreachable_default_argument_value' => true,
'no_useless_else' => true,
'no_useless_return' => true,
'ordered_class_elements' => true,
'ordered_imports' => true,
'php_unit_construct' => true,
'php_unit_test_class_requires_covers' => true,
'php_unit_dedicate_assert' => true,
'phpdoc_add_missing_param_annotation' => true,
'phpdoc_order' => true,
'phpdoc_types_order' => ['null_adjustment' => 'always_last'],
'semicolon_after_instruction' => true,
'single_line_comment_style' => true,
'visibility_required' => ['const', 'property', 'method'],
'yoda_style' => true,
])
->setFinder(
PhpCsFixerFinder::create()
->exclude(__DIR__. '/vendor/*')
->in([
__DIR__. '/src'
])) ;
Em seguida, você também desejará criar o arquivo XML para complementar o arquivo acima. Você notará que no arquivo que estou fornecendo, isso é o que uso para meu trabalho na Pressware. Além disso, também reconhece o diretório de testes.
Neste ponto, não temos nenhum teste de unidade escrito, mas se você optar por introduzi-lo em seu widget, ele estará pronto para tratá-lo adequadamente.
<?xml version="1.0"?>
<ruleset name="Pressware">
<description>Pressware, LLC Coding Standards</description>
<!-- Scan all files in directory -->
<file>./src</file>
<file>./tests</file>
<exclude-pattern>./tests/phpunit/*</exclude-pattern>
<!-- Scan only PHP files -->
<arg name="extensions" value="php"></arg>
<!-- Show colors in console -->
<arg value="-colors"></arg>
<!-- Show sniff codes in all reports -->
<arg value="ns"></arg>
<!-- Use PSR-2 as a base -->
<rule ref="PSR2"></rule>
<rule ref="Generic.Arrays.DisallowLongArraySyntax.Found" ></rule>
<!-- Force 2 spaces indentation -->
<rule ref="Generic.WhiteSpace.ScopeIndent">
<properties>
<property name="indent" value="4"></property>
<property name="tabIndent" value="false"></property>
</properties>
</rule>
</ruleset>
Há apenas um pequeno conjunto de configuração que eu especifico aqui, mas achei que é mais do que suficiente para minhas necessidades até agora. Conforme eu descobrir mais ou optar por usar mais, certamente atualizarei o conteúdo nos próximos posts.
Configurar PHPMD
E, finalmente, precisamos configurar o PHP Mess Detector (ou PHPMD). Felizmente, isso usa um arquivo XML que usará conjuntos de regras conforme definido no pacote instalado pelo Composer. Tudo o que precisamos fazer é referenciar a regra no arquivo de configuração.
Em segundo lugar, também forneceremos uma pequena exclusão para um nome ShortVariable, como você verá na seguinte essência :
<?xml version="1.0" encoding="UTF-8" ?>
<ruleset
name="VersionEyeModule rules"
xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation="http://pmd.sf.net/ruleset_xml_schema.xsd"
>
<rule ref="rulesets/cleancode.xml" ></rule>
<rule ref="rulesets/codesize.xml" ></rule>
<rule ref="rulesets/controversial.xml" ></rule>
<rule ref="rulesets/design.xml" ></rule>
<rule ref="rulesets/unusedcode.xml" ></rule>
<rule ref="rulesets/naming.xml">
<exclude name="ShortVariable"></exclude>
</rule>
<rule ref="rulesets/naming.xml/ShortVariable"
since="0.2"
message="Avoid variables with short names like {0}. Configured minimum length is {1}."
class="PHPMDRuleNamingShortVariable"
externalInfoUrl="http://phpmd.org/rules/naming.html#shortvariable">
<priority>3</priority>
<properties>
<property name="minimum" description="Minimum length for a variable, property or parameter name" value="3"></property>
<property name="exceptions" value="id,q,w,i,j,v,e,f,fp" ></property>
</properties>
</rule>
</ruleset>
E uma vez que tudo isso esteja no lugar, devemos ser capazes de executar o GrumPHP novamente, a partir da linha de comando, e ter um conjunto de resultados ligeiramente diferente.
Executando GrumPHP novamente
Digite o seguinte no seu terminal:
$ vendor/bin/grumphp run
E você deve ver algo assim:
Resultados diferentes da primeira vez, né? Isso ocorre porque estamos violando algumas regras e padrões que são uma parte moderna do PHP e do desenvolvimento orientado a objetos.
E é isso que vamos esclarecer no próximo post.
Chegando
Então, de onde vem a natureza orientada a objetos disso? Até este ponto, falamos sobre o uso da API Widgets como um modelo orientado a objetos para escrever código orientado a objetos no WordPress.
Parte do que fizemos até agora foi exatamente isso (conversando sobre seus princípios, vendo como está organizado e muito mais).
Mas, como mencionei no início deste post, colocar ferramentas de qualidade de código primeiro nos fornece uma base que podemos usar à medida que refatoramos o clichê (o que claramente precisamos fazer, dada a quantidade de vermelho mostrada pelo GrumPHP).
E é por aí que vamos começar no próximo post desta série.


