<![CDATA[MageBR]]>http://blog.magebr.com/pt/http://blog.magebr.com/pt/favicon.pngMageBRhttp://blog.magebr.com/pt/Ghost 3.15Tue, 19 May 2020 02:26:12 GMT60<![CDATA[Novo MageBR!]]>http://blog.magebr.com/pt/novo-magebr/5ea3a22d01ef706c1698d8b0Sat, 25 Apr 2020 02:43:29 GMT

Sejam bem vindos ao novo blog! Nos últimos dois anos utilizamos o Drupal e antes utilizamos o Drupal. Eu adoro trabalhar com servidores, mas este blog é bem simples com textos e algumas imagens. A maioria do conteúdo do nosso blog é estático.

E é por isso que decidi mudar o blog para a plataforma Ghost, ele é bem simples de utilizar, manter e é super RÁPIDO! E para deixar tudo melhor, estamos rodando nosso blog 100% serverless!

Sim! Nosso blog roda no AWS S3 e Cloudflare para CDN. Irei explicar mais em nosso novo blog sobre tecnologia Cloud (somente em Inlgês).
Isso mesmo! Estamos construindo o novo blog!

Eu adorei usar o sistema Drupal, ele é bem completo, mas tem muito mais funcionalidade do que eu utilizava. Além de ter atualizações constantes (não que esteja reclamando), mas era difícil manter tudo atualizado e seguro.

O nosso novo blog é muito mais seguro, não há nenhum dado sendo hospedado, toda página aqui é um arquivo html! Pode demorar alguns minutos para gerar as páginas e mandar para o S3, mas acredito que seja a decisão correta.

Tenho vários tutoriais, então não se esqueça de se inscrever no nosso newsletter!

Espero que gostem da mudança!

]]>
<![CDATA[Novidade do MageBR]]>http://blog.magebr.com/pt/novidade-do-magebr/5ea3a20001ef706c1698d8a2Wed, 15 Apr 2020 02:44:00 GMT

Este será um post rápido.

Em breve estarei migrando o MageBR para um novo sistema para blog e também uma nova hospedagem. Eu já usei Wordpress no passado e decidi não voltar para ele.
Eu tenho usado Drupal nos últimos 3 anos e gostei muito, mas acho que é hora de mudar para um sistema mais simples. Estou pesquisando algumas soluções e tenho testado uma em particular. Eu irei revelar o novo sistema quando o novo blog estiver no ar, mas desta vez não perderemos os tutoriais como aconteceu na migração do Wordpress para Drupal.

Irei migrar todos os tutoriais e acredito que isso me dará mais tempo para escrever novos posts. Eu também irei abrir um novo blog específico para cloud e postarei o novo link assim que a nova versão do MageBR for liberada.

Fique de olho nas próximas semanas para algo novo!

]]>
<![CDATA[Problemas quando rodar static content deploy com EFS]]>http://blog.magebr.com/pt/problemas-quando-rodar-static-content-deploy-com-efs/5ea3a1d001ef706c1698d896Wed, 24 Apr 2019 05:00:00 GMT

E este artigo é mais um artigo sobre como o Magento 2 pode ser irritante e como ele não foi feito para rodar de forma escalável.

Bom, estamos vendo vários errors quendo rodando o static content deploy com a opção --jobs:

magento setup:static-content:deploy --jobs 5

A opção --jobs foi feita para que vários temas sejam processados em paralelo. Se você colocar 5 jobs, irá processar 5 temas em paralelo.
No momento cada loja tem somente um tema sendo usado, mas eles dependem no tema base personalizado e também no tema Magento Blank. Quando você roda o comando sem a opção --jobs o Magento vai processar o tema blank, depois processa o tema base personalizado e finalmente o seu tema personalizado.

Mas se você tiver vários temas ou até somente um no EFS, a rede pode ser um bottleneck, assim como o EFS que é lento já que é tudo feito via conexão NFS, então não será tão rápido como fazer o deploy em um SSD local e é justamente ao adicionar a opção --jobs ajuda no deploy do conteúdo estático. Mas se você tiver vários arquivos para cada tema pode demorar vários minutos e você receberá este erro:

In Queue.php line 366:

Error while waiting for package deployed: 42; Status: 0


setup:static-content:deploy [-f|--force] [-s|--strategy [STRATEGY]] [-a|--area [AREA]] [--exclude-area [EXCLUDE-AREA]] [-t|--theme [THEME]] [--exclude-theme [EXCLUDE-THEME]] [-l|--language [LANGUAGE]] [--exclude-language [EXCLUDE-LANGUAGE]] [-j|--jobs [JOBS]] [--symlink-locale] [--content-version CONTENT-VERSION] [--refresh-content-version-only] [--no-javascript] [--no-css] [--no-less] [--no-images] [--no-fonts] [--no-html] [--no-misc] [--no-html-minify] [--] [<languages>...]

Até existe um issue aberto no repositório do Magento 2 e eu adicionei um comentário lá: https://github.com/magento/magento2/issues/21852

O problema pode ser causado por este código: https://github.com/magento/magento2/blob/2.3-develop/app/code/Magento/Deploy/Process/Queue.php#L391
E a função responsável pelo timeout: https://github.com/magento/magento2/blob/2.3-develop/app/code/Magento/Deploy/Process/Queue.php#L372
E tudo isso aponta para a const DEFAULT_MAX_EXEC_TIME = 400;
https://github.com/magento/magento2/blob/2.3-develop/app/code/Magento/Deploy/Process/Queue.php#L32

Então se o static content deploy roda por mais de 400 segundos, ele irá falhar. Mas o Magento consertou a ferramenta ECE deles adicionando uma opção para aumentar o timeout: https://github.com/magento/ece-tools/pull/418
Mas no momento o problema não foi corrigido no Magento Open Source ou Commerce Edition.

Então o que você pode fazer: Bom, no momento estamos colocando a informação do tema para cada loja em um microservice e quando há um deploy de código nós pegamos a informação do microservice e fazemos o deploy somente do tema associado à loja. Então por exemplo o tema MageBR/mytheme associado à sua loja poderia rodar assim:

magento setup:static-content:deploy --theme MageBR/mytheme

Desta forma irá acelerar o deploy do conteúdo estático e não aparecer erros.

Deploy using quick strategy
frontend/Magento/blank/en_US 2456/2456 ============================ 100% % 1 min
frontend/MageBR/base/en_US 2765/2765 ============================ 100% % 2 mins
frontend/MageBR/mytheme/en_US 2765/2765 ============================ 100% % 2 mins

Execution time: 483.77401208878

Mas seria muito melhor se puder rodar o comando com a opção --jobs para acelerar ainda mais o processo. Você pode fazer um teste adicionando a opção --jobs com a opção --theme e se não demorar muito o deploy, não haverá problema, mas seria uma boa ótimo ter uma opção para aumentar o timeout diretamente na linha de comand.

Espero que tenha gostado do artigo, deixe seu comentário e não se esqueça de compartilhar!

]]>
<![CDATA[Rodando Magento 2 Crons com Queue no Kubernetes ou Docker]]>http://blog.magebr.com/pt/rodando-magento-2-crons-com-queue-no-kubernetes-ou-docker/5ea3a17701ef706c1698d887Sun, 21 Apr 2019 21:37:00 GMT

Vou começar dizendo que este artigo será rápido e simples, mas foi uma dor de cabeça achar os problemas que encontramos rodando Magento com cron e queues no Kubernetes (ou até Docker).
Configurar o cron foi bem simples e a documentação do Magento é muito boa: https://devdocs.magento.com/guides/v2.3/config-guide/cli/config-cli-subcommands-cron.html

Mas o problema não é somente rodar os crons, mas se você rodar os crons enquanto tiver o queue ativado usando RabbitMQ, que vai utilizar os consumers. Você pode ler mais sobre queues e consumers aqui: https://devdocs.magento.com/guides/v2.3/config-guide/mq/rabbitmq-overview.html

Vamos dizer que você adicionou um novo módulo que irá consumir os queues ou você adicionou a configuração no app/etc/env.php:

'queue' =>
array (
'amqp' =>
array (
'host' => 'rabbitmq.example.com',
'port' => '11213',
'user' => 'magento',
'password' => 'magento',
'virtualhost' => '/',
'ssl' => true,
'ssl_options' => [
'cafile' => '/etc/pki/tls/certs/DigiCertCA.crt',
'certfile' => '/path/to/magento/app/etc/ssl/test-rabbit.crt',
'keyfile' => '/path/to/magento/app/etc/ssl/test-rabbit.key'
],
),
),

Ou você adicionou o código abaixo durante a instalação:

--amqp-host="<hostname>" --amqp-port="5672" --amqp-user="<user_name>" --amqp-password="<password>" --amqp-virtualhost="/"

Bom, agora o Magento irá usar os consumers para trabalhar os queues. Aqui encontramos dois problemas. O primeiro é que sempre que o cron rodar, irá gerar processos no background com os consumers, como por exemplo:

$ kubectl exec -n my-store magento-75788af261-adwdc -c magento ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 18048 1932 ? Ss 14:13 0:00 /bin/bash /setup.sh
root 16 0.0 0.0 4284 588 ? S 14:13 0:00 /bin/sh /usr/sbin/apache2ctl -D FOREGROUND
root 18 0.0 0.0 274652 19168 ? S 14:13 0:00 /usr/sbin/apache2 -D FOREGROUND
www-data 20 0.9 0.2 344228 90216 ? S 14:13 1:50 /usr/sbin/apache2 -D FOREGROUND
www-data 24 0.9 0.2 344232 86344 ? S 14:13 1:41 /usr/sbin/apache2 -D FOREGROUND
www-data 59 0.0 0.2 291524 94128 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start commonErrorManagement --pid-file-path=commonErrorManagement-magento76799dc865rglqw.pid --max-messages=10000
www-data 61 0.0 0.2 291524 94024 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start ping --pid-file-path=ping-magento76799dc865rglqw.pid --max-messages=10000
www-data 63 0.0 0.3 317288 118348 ? S 14:15 0:05 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start productConsumer --pid-file-path=productConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 65 0.0 0.2 293740 95408 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start stockConsumer --pid-file-path=stockConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 67 0.0 0.2 293752 95652 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start productReturnUpdatedConsumer --pid-file-path=productReturnUpdatedConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 69 0.0 0.3 293704 97224 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start refundUpdatedConsumer --pid-file-path=refundUpdatedConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 71 0.0 0.3 317288 118240 ? S 14:15 0:04 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start orderCancellation --pid-file-path=orderCancellation-magento76799dc865rglqw.pid --max-messages=10000
www-data 73 0.0 0.3 317288 118116 ? S 14:15 0:04 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start orderGetNotifications --pid-file-path=orderGetNotifications-magento76799dc865rglqw.pid --max-messages=10000
www-data 75 0.0 0.3 317288 118440 ? S 14:15 0:04 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start orderResendNotification --pid-file-path=orderResendNotification-magento76799dc865rglqw.pid --max-messages=10000
www-data 77 0.0 0.3 317292 118508 ? S 14:15 0:04 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start orderConsumer --pid-file-path=orderConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 79 0.0 0.2 291524 93944 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start orderUpdatedConsumer --pid-file-path=orderUpdatedConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 82 0.0 0.3 295756 97992 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start customerShipmentDoneConsumer --pid-file-path=customerShipmentDoneConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 84 0.0 0.2 291656 93784 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start orderLineCancelledConsumer --pid-file-path=orderLineCancelledConsumer-magento76799dc865rglqw.pid --max-messages=10000
www-data 86 0.0 0.2 291656 94968 ? S 14:15 0:03 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start shippingAddressUpdated --pid-file-path=shippingAddressUpdated-magento76799dc865rglqw.pid --max-messages=10000
www-data 92 0.0 0.3 317292 119656 ? S 14:15 0:04 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start serviceBusDiscover --pid-file-path=serviceBusDiscover-magento76799dc865rglqw.pid --max-messages=10000
www-data 94 0.0 0.3 317292 118524 ? S 14:15 0:04 /usr/local/bin/php /var/www/html/bin/magento queue:consumers:start async.operations.all --pid-file-path=async.operations.all-magento76799dc865rglqw.pid --max-messages=10000
www-data 178 1.6 0.2 336144 81796 ? S 16:24 0:53 /usr/sbin/apache2 -D FOREGROUND
www-data 179 1.2 0.2 336220 83776 ? S 16:24 0:42 /usr/sbin/apache2 -D FOREGROUND
www-data 195 1.3 0.2 336160 81964 ? S 16:27 0:42 /usr/sbin/apache2 -D FOREGROUND
www-data 198 1.0 0.2 333196 74692 ? S 16:30 0:31 /usr/sbin/apache2 -D FOREGROUND
www-data 199 1.0 0.2 333196 74696 ? S 16:30 0:31 /usr/sbin/apache2 -D FOREGROUND
www-data 200 1.0 0.2 333212 74708 ? S 16:30 0:29 /usr/sbin/apache2 -D FOREGROUND
www-data 201 1.3 0.2 333140 74632 ? S 16:30 0:40 /usr/sbin/apache2 -D FOREGROUND
www-data 210 1.1 0.2 333140 74636 ? S 16:30 0:34 /usr/sbin/apache2 -D FOREGROUND
root 440 0.0 0.0 36640 2712 ? Rs 17:19 0:00 ps aux

Como pode ver acima, existe vários consumers rodando, eles são todos do Magento. Se você tiver algum queue customizado, ele irá aparecer na lista também. Agora é que o segundo problema aparece.
Magento tem na documentação que cada consumer processa 1000 mensagens e depois finaliza: https://devdocs.magento.com/guides/v2.3/config-guide/mq/manage-message-queues.html#configuration

max_messages - the maximum number of messages for each consumer that must be processed before consumer terminate, by default is 1000. If it is 0, then the consumer never stops working.

Mas como você pode ver acima, está configurado para 10000 e podemos confirmar no código: https://github.com/magento/magento2/blob/2.3-develop/app/code/Magento/MessageQueue/Model/Cron/ConsumersRunner.php#L114

Sem problemas se você estiver rodando o cron em um único ou vários servidores, mas assim que você inicializa o cron os processos no background também inicializam e somente finalizam quando 10000 mensagens são processadas (por padrão). O cron irã rodar até que o timeout do Kubernetes aconteça (padrão de uma hora).
Então poderiamos configurar o --max-messages para 1, mas da forma que o Magento funciona SEMPRE irá esperar por aquela 1 mensagem, ao invéz de checar se o queue está vazio e terminar. Existe um issue aberto no repositório deles, mas sem sinal de que algo será feito: https://github.com/magento/magento2/issues/17951

Então o que fazer?

Bom, por agora decidimos rodar o Supervisord no seu próprio pod e os consumers dentro do Supervisord. E não esqueça de desabilitar os consumers durante o cron no env.php:

...
'cron_consumers_runner' => array(
'cron_run' => false
),
...

Espero que um dia a Magento considere fazer o Magento pronto para DevOps.
Caso você tenha feito de outra forma, não deixe de deixar seu comentário.

]]>
<![CDATA[Configurando o Mecanismo de Busca de Catálogo via CLI]]>http://blog.magebr.com/pt/configurando-o-mecanismo-de-busca-de-catalogo-via-cli/5ea3a11301ef706c1698d86eFri, 15 Feb 2019 20:37:00 GMT

Desde que instalamos o Magento 2.3 estamos recebendo a notícia que o MySQL para a Busca de Catálogo será descontinuada (deprecated). Não temos problema com isso já que iremos usar Elasticsearch, mas temos que configurar o Magento com as informações corretas quando os containers iniciam e não de forma manual pelo admin, mas a configuração pode ser feita pelo CLI através de scripts logo após o container iniciar.

Se vocẽ quiser informação sobre o elasticsearch e como configurar pelo admin, você pode achar essa informação na documentação do Magento aqui: https://devdocs.magento.com/guides/v2.3/config-guide/elasticsearch/configure-magento.html

Para configurar o elasticsearch pelo CLI, você provavelmente só precisará desses dois comandos:

magento config:set catalog/search/engine 'elasticsearch6'
magento config:set catalog/search/elasticsearch6_server_hostname 'elasticsearch-hostname.env'

A primeira opção é o engine que pode ser: mysql, elasticsearch, elasticsearch5 ou elasticsearch6
A segunda opção é o hostname e você pode usar IP ou DNS. Nós temos o Magento configurado usando cluster de Kubernetes, então elasticsearch tem seu próprio container rodando e o hostname é baseado no nome da loja. Você então pode configurar usando variáveis:

magento config:set catalog/search/elasticsearch6_server_hostname "elasticsearch-$MY_VARIABLE.env"

Verifique que agora colocamos entre aspas duplas já que é uma variável. Você também pode configurar outras opções:

magento config:set catalog/search/elasticsearch6_server_port '9200'
magento config:set catalog/search/elasticsearch6_index_prefix 'magento2'
magento config:set catalog/search/elasticsearch6_enable_auth '0'
magento config:set catalog/search/elasticsearch6_server_timeout '15'

Estas configurações são padrões para elasticsearch e elasticsearch6, então modifique somente o que precisar.

Espero que tenham gostado do artigo e até o próximo.

]]>
<![CDATA[Atualize Download Links dos Pedidos]]>http://blog.magebr.com/pt/atualize-download-links-dos-pedidos/5ea3a0d501ef706c1698d85fMon, 17 Dec 2018 02:38:00 GMT

Se você criar um produto digital para pré venda (é necessário um módulo para isso) e por acaso ainda não tenha o link ou arquivo que será usado no produto, mas você precisa criar o product e liberar para seus clientes comprarem (pré venda). Provavelmente você usará um link como "http://DEFINIR// ou somente escrever "DEFINIR" ou fazer o upload de um arquivo que não é o correto já que os clientes não poderão baixar. Isso também se aplica a backorders ou pedidos normais que por algum motivo você quer que os clientes possam comprar, mas o link/arquivo não estará disponível até certa data.

Também se aplica caso você queira atualizar um link ou arquivo que possa trocar e você precisa que todos os seus clientes tenham o novo link/arquivo atualizados. Infelizmente o Magento não atualiza os pedidos com os novos links/arquivos e isso é BEM chato quando você tem vários pedidos com os exemplos dados. Para resolver o problema eu resolvi criar um módulo que faz justamente isso. Quando você atualiza o link/arquivo do produto, ele atualiza TODOS os pedidos com aquele produto.

Esta é a tabela no banco de dados responsável pelos items comprados com links/arquivos: downloadable_link_purchased_item
Eu fiz um pedido teste em uma loja no meu ambiente local e eu verifiquei o link_url desta tabela e podemos ver o link do pedido:

SELECT link_url FROM downloadable_link_purchased_item;
+----------------------+
| link_url |
+----------------------+
| http://tbd/somefile.zip |
+----------------------+
1 row in set (0.00 sec)

E também podemos confirmar que o link é do produto:

SELECT product_id, sku, link_url
-> FROM downloadable_link
-> INNER JOIN catalog_product_entity
-> WHERE entity_id = 3;
+------------+-----------------+----------------------+
| product_id | sku | link_url |
+------------+-----------------+----------------------+
| 3 | digital_product | http://tbd/somefile.zip |
+------------+-----------------+----------------------+

Também podemos confirmar que há um pedido com esse produto:

SELECT c.product_id, b.sku, c.link_url, b.order_id
-> FROM downloadable_link c
-> INNER JOIN catalog_product_entity a
-> INNER JOIN sales_flat_order_item b
-> WHERE entity_id = 3;
+------------+-----------------+----------------------+----------+
| product_id | sku | link_url | order_id |
+------------+-----------------+----------------------+----------+
| 3 | digital_product | http://tbd/somefile.zip | 1 |
+------------+-----------------+----------------------+----------+

Agora eu irei atualizar o link do produto de somefile.zip para myrealfile.zip no admin do Magento e iremos ver que nada acontece para o pedido na tabela downloadable_link_purchased_item.
Primeiro vamos verificar o downloadable_link para ter certeza que o link foi atualizado:

SELECT link_url FROM downloadable_link WHERE product_id = 3;
+---------------------------+
| link_url |
+---------------------------+
| http://tbd/myrealfile.zip |
+---------------------------+

Ok, então o produto tem o novo link, so the product has the new link. Agora vamos ver os pedidos:

SELECT item_id, link_url FROM downloadable_link_purchased_item;
+---------+-------------------------+
| item_id | link_url |
+---------+-------------------------+
| 1 | http://tbd/somefile.zip |
+---------+-------------------------+

Bom, parece que ainda está com o link antigo, mas novos pedidos vão utilizar myrealfile.zip. Mas seria ótimo se ao atualizar o link ou arquivo do produto também atualizasse os pedidos. E é justamente por isso que criei o módulo MageBR_UpdateLinksPurchased e é totalmente gratuito para utilizar. Você pode fazer o download da versão mais nova aqui: here: https://github.com/CajuCLC/MageBR_UpdateLinksPurchased/releases/latest
Ou se deseja contribuir para deixar o módulo ainda melhor: https://github.com/CajuCLC/MageBR_UpdateLinksPurchased

Após instalar o módulo e atualizar os caches, vamos modificar um produto digital novamente, agora iremos mudar o link de myrealfile.zip para updatedlink.zip.
Vamos conferir se o produto tem o novo link:

SELECT link_url FROM downloadable_link WHERE product_id = 3;
+----------------------------+
| link_url |
+----------------------------+
| http://tbd/updatedlink.zip |
+----------------------------+

E o pedido também dever ter o novo link:

SELECT item_id, link_url FROM downloadable_link_purchased_item;
+---------+----------------------------+
| item_id | link_url |
+---------+----------------------------+
| 1 | http://tbd/updatedlink.zip |
+---------+----------------------------+

Pronto, todos os pedidos irão ter o novo link ou arquivo. MAS ainda não terminamos. Se você receber um erro ao tentar salvar o produto dizendo que order id não pode ser NULL, significa que você tem pedidos que foram deletados e não cancelados. Quando você deleta um pedido acaba deixando várias outras coisas sem estar relacionada a um pedido (NULL). Você pode checar rodando as queries abaixo:

SELECT * FROM downloadable_link_purchased WHERE order_id IS NULL;
SELECT * FROM downloadable_link_purchased_item WHERE order_item_id IS NULL;

Se qualquer query retornou algo, então você precisa remover elas. Na maioria das vezes não há problema, mas por favor criei um backup e tenha certeza que você pode deletar. Não nos responsabilizamos por qualquer problema.

DELETE FROM downloadable_link_purchased_item WHERE order_item_id IS NULL;
DELETE FROM downloadable_link_purchased WHERE order_id IS NULL;

E chegamos ao final, tudo estará funcionando como deve agora.

Caso tenha gostado deste tutorial e módulo, por favor compartilhe.

]]>
<![CDATA[Bug Email Transicional e New Relic]]>http://blog.magebr.com/pt/bug-email-transicional-new-relic/5e9bf122d99bc630f648e0bfSat, 25 Aug 2018 00:48:00 GMT

Recentemente tive um problema com o email transicional em um Magento EE 1.13.0 rodando Debian no container e o agente PHP da New Relic instalado.
Quando na página para criar um novo template, se você tentar carregar um template em HTML, ele fica girando e depois não carrega o template. Mas funciona com template em texto.

Durante nossos testes identificamos que o agente da New Relic estava adicionando um JavaScript à requisição, que quebrava o carregamento. Por motivos de segurança irei colocar somente parte do JavaScript que era inserido:

s=NREUM;"undefined"==typeof window.newrelic&&(newrelic=s)

Existe explicação do agente aqui: https://docs.newrelic.com/docs/browser/new-relic-browser/getting-started/introduction-new-relic-browser
A New Relic explica como desativar o agente para uma função específica: https://docs.newrelic.com/docs/agents/php-agent/php-agent-api/newrelic_disable_autorum

A função responsável em carregar o template é: public function defaultTemplateAction()
Que está no arquivo: app/code/core/Mage/Adminhtml/controllers/System/Email/TemplateController.php

Basta adicionar o código fornecido pela New Relic logo no começo desta função para não ter mais problemas:

public function defaultTemplateAction()
{
if (extension_loaded('newrelic')) {
newrelic_disable_autorum();
}
$template = $this->_initTemplate('id');
$templateCode = $this->getRequest()->getParam('code');
$template->loadDefault($templateCode, $this->getRequest()->getParam('locale'));
$template->setData('orig_template_code', $templateCode);
$template->setData('template_variables', Zend_Json::encode($template->getVariablesOptionArray(true)));
$templateBlock = $this->getLayout()->createBlock('adminhtml/system_email_template_edit');
$template->setData('orig_template_used_default_for', $templateBlock->getUsedDefaultForPaths(false));
$this->getResponse()->setBody(Mage::helper('core')->jsonEncode($template->getData()));
}

Como não é recomendado atualizar o arquivo core do Magento, copie o arquivo para a pasta local: app/code/local/Mage/Adminhtml/controllers/System/Email/TemplateController.php
Agora você pode fazer a alteração diretamente neste arquivo. Caso o seu Magento tenha bastante modificações, é capaz de não funcionar desta maneira.

É por isso que criei um módulo bem simples para ficar fácil a implementação. Você pode baixar ele aqui: https://github.com/CajuCLC/MageBR_Newrelicfix/releases/latest
Caso queira ajudar no projeto: https://github.com/CajuCLC/MageBR_Newrelicfix

Eu não consegui replicar o problema em servidores utilizando CentOS 6 e Amazon Linux.

Espero que este tutorial tenha servidor e ajudado vocês. Não se esqueça de adicionar nosso site aos favoritos.

Até a próxima!

]]>
<![CDATA[Erro de Extensão ao Exportar Relatório em XML ou CSV]]>http://blog.magebr.com/pt/erro-de-extensao-ao-exportar-relatorio-em-xml-ou-csv/5e9bf733d99bc630f648e0eeWed, 28 Mar 2018 04:55:00 GMT

Olá à todos, temos mais um novo tutorial para você corrigir um possível problema em sua loja.

Você já se deparou com o problema de quando exporta o seu relatório em XML ou CSV o arquivo vem com uma extensão assim:

invoiced.csv-, attachment
invoiced.xml-, attachment

Pois é, isso é bem comum para que usa algumas versões do Magento e também de algumas versões de alguns navegadores. A solução é bem simples.

Abra o arquivo: app/code/core/Mage/Core/Controller/Varien/Action.php

Procure por:

->setHeader('Content-Disposition', 'attachment; filename="'.$fileName.'"', true)

Altere para:

->setHeader('Content-Disposition', 'attachment; filename="'.$fileName.'";', true)

Pronto, agora limpe o cache e faça outro teste.

Até o próximo tutorial aqui no MageBR

]]>
<![CDATA[Magento MySQL Master/Slave]]>http://blog.magebr.com/pt/magento-mysql-master-slave/5ea3a08001ef706c1698d852Wed, 28 Mar 2018 04:49:00 GMT

Este é um tutorial muito simples sobre como você pode configurar o Magento para trabalhar com múltiplos servidores MySQL, caso você tenha a configuração Master/Slave.

Primeiro você precisa de uma configuração MySQL master/Slave, se você ainda não tem configurado há um tutorial aqui: https://dev.mysql.com/doc/refman/5.7/en/replication-howto.html

Caso esteja utilizando um serviço de banco de dados como AWS RDS fica muito mais fácil. Somente utilize o DNS da réplica na configuração abaixo.

No Magento abra o arquivo app/etc/local.xml e você encontrará a parte abaixo:

<default_setup>
<connection>
<host><![CDATA[10.x.x.x]]></host>
<username><![CDATA[magento]]></username>
<password><![CDATA[PassWord]]></password>
<dbname><![CDATA[magento]]></dbname>
<initStatements><![CDATA[SET NAMES utf8]]></initStatements>
<model><![CDATA[mysql4]]></model>
<type><![CDATA[pdo_mysql]]></type>
<pdoType><![CDATA[]]></pdoType>
<active>1</active>
</connection>
</default_setup>

Esta é a configuração padrão do Magento, é necessário adicionar a opção de MySQL Slave para funcionar.
Para configurar adicione o código abaixo logo após </default_setup>:

<default_read>
<connection>
<use/>
<host><![CDATA[10.x.x.x]]></host>
<username><![CDATA[magento]]></username>
<password><![CDATA[PassWord]]></password>
<dbname><![CDATA[magento]]></dbname>
<type>pdo_mysql</type>
<model>mysql4</model>
<initStatements>SET NAMES utf8</initStatements>
<active>1</active>
</connection>
</default_read>

Você pode ter quantos MySQL slaves necessitar.

]]>
<![CDATA[Login na Lateral]]>http://blog.magebr.com/pt/login-na-lateral/5e9bf841d99bc630f648e107Wed, 28 Mar 2018 04:38:00 GMT

Tutorial bastante simples onde iremos colocar o login na lateral desejada.

Primeiro abra o arquivo: /app/design/frontend/base/default/layout/customer.xml

Procure e comente o name="right"

Agora vamos abrir o arquivo app/code/local/Mage/Customer/Block/Form/Login.php
Agora vamos comentar esta linha também:

$this->getLayout()->getBlock(’head’)->setTitle(Mage::helper(’customer’)->__(’Customer Login’));

Somente isto. Sucesso.

]]>
<![CDATA[Corrigindo Erro “[unknown object].fireEvent()”]]>http://blog.magebr.com/pt/corrigindo-erro-unknown-object-fireevent/5ea3a02801ef706c1698d845Wed, 28 Mar 2018 04:21:00 GMT

Muitas pessoas já encontraram esse erro no Magento quando abre algum cadastro de um cliente ou criar um pedido pelo admin. O erro que aparece é este:

error: error in [unknown object].fireEvent():
event name: address_country_changed
error message: zipElement.up(...).down(...) is undefined

Eu já me deparei com este erro, mas vamos resolver.

  • Abra o arquivo app/design/adminhtml/default/default/template/directory/js/optional_zip_countries.phtml
  • Procure pela função function setPostcodeOptional(zipElement, country)
  • Procure pela linha abaixo:
zipElement.up(1).down('label > span.required').hide();
  • Troque pelo código abaixo:
var zipElementLabel = zipElement.up(1).down('label > span.required');
if (zipElementLabel)
zipElementLabel.hide();
  • No mesmo arquivo procure pelo código abaixo:
zipElement.up(1).down('label > span.required').show();
  • E troque pelo seguinte código:
var zipElementLabel = zipElement.up(1).down('label > span.required');
if (zipElementLabel)
zipElementLabel.show();

Salve o arquivo, limpe o cache e veja que você não recebe mais o erro.

Fonte: http://premius.net/blog/php/116-fixing-magento-error-error-in-unknown-object-fireevent.html

]]>
<![CDATA[Usando Mailgun com Magento]]>http://blog.magebr.com/pt/usando-mailgun-com-magento/5ea39ee701ef706c1698d837Wed, 28 Mar 2018 03:51:00 GMT

Quando você configura tudo certo para enviar o email, agora o email não chega no INBOX do cliente e acaba caindo no SPAM. Mas até quando o email vai parar na pasta INBOX do cliente, mas ele diz que não recebeu o email, como você verifica se ele realmente recebeu ou não? Como verificar se ele abriu o email?

Por isso que hoje utilizo MailGun da RackSpace. Cliente cloud da RackSpace recebe 50 mil emails por email (envio e recebimento), é muito email para lojas pequenas e médias. Temos duas formas de configurar o MailGun, o que mais utilizo é configurando um Postfix SMTP relay diretamente no servidor, assim você nem precisa configurar o Magento ou instalar alguma extensão. Para esse você precisa utilizar um servidor dedicado ou cloud. Você precisará configurar o MailGun primeiro, para fazer isso acesse esse tutorial: Configurando Mailgun

Vamos à primeira forma de configurar, utilizando o Postfix. Primeiro precisamos instalar o Postfix e ferramentas SSAL:

  • CentOS:
yum install postfix cyrus-sasl-plain cyrus-sasl-md5
  • Ubuntu:
apt-get update apt-get install postfix libsasl2-modules

Agora vamos configurar o Postfix, para isso abra o arquivo /etc/postfix/main.cf

smtp_sasl_auth_enable = yes
relayhost = smtp.mailgun.org
smtp_sasl_security_options = noanonymous
smtp_sasl_password_maps=hash:/etc/postfix/sasl_passwd

Agora vamos configurar sasl_passwd com o usuário e senha do Mailgun:

echo 'smtp.mailgun.org [email protected]:senha' > /etc/postfix/sasl_passwd

Você precisa alterar o [email protected] e senha. Para isso acesse o painel do Mailgun clique em Domains e depois no seu domínio. Nesta página irá aparecer o Default SMTP Login e Default Password, altere as iformações no sasl_passwd.

O próximo passo é alterar as permissões do sasl_passwd:

chmod 600 /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd

Por último reinicie Postfix:

service postfix restart

Agora todos os emails que forem enviados pelo Magento serão enviados utilizando o Mailgun. Caso você possua mais de uma loja e são domínios diferentes, você pode configurar Postfix por domínio, ou pode utilizar somente um domínio, todos os outros emails ainda serão ser autenticados com o configurado.

Caso você não tenha um servidor que possa instalar o Postfix, você pode utilizar esta extensão: SMTP Pro Email – Free Custom SMTP Email

A configuração é muito simples, somente marcar como Custom SMTP e colocar autenticação (PLAIN) o usuário (email), senha, host (smtp.mailgun.org) e porta (25, 587 ou 465).
Todas essas informações podem ser encontradas no painel do Mailgun, clique em Domains e depois selecione o seu domínio. Pronto, seu Magento irá enviar os emails utilizando o SMTP do Mailgun.

]]>
<![CDATA[Atualize o Magento para versão 1.9]]>http://blog.magebr.com/pt/atualize-o-magento-para-versao-1-9/5ea39eb301ef706c1698d829Wed, 28 Mar 2018 02:54:00 GMT

Seria ótimo se tivesse um botão no admin para fazer a atualização, mas não é tão simples assim. Você pode estar pensando, “mas e Magento Connect?” Ele não é tão eficiente assim, acredite. Hoje neste tutorial irei explicar como fazer a atualização de sua loja Magento. Este tutorial foi testado com a versão 1.5.1.0 para 1.9.0.1.

Para este tutorial você irá precisar:

* Acesso SSH ao servidor
* Conhecimento de comandos Shell
* Conhecimentos do Magento
* Conhecimentos de MySQL

Caso você não tenha conhecimento necessário PARE agora e contrate alguém para fazer a sua atualização. Este tutorial PODE e IRÁ quebrar a sua loja se você não souber o que está fazendo. Qualquer problema causado por este tutorial não é de responsabilidade da MagentoBR e não há nenhuma garantia de funcionamento ou de suporte!

Nós recomendamos que a atualização seja feito em ambiente de desenvolvimento e não no ambiente de produção! Faça vários testes no seu ambiente de desenvolvimento antes de atualizar o ambiente de produção.

Antes de tudo você precisa fazer BACKUP!

Para este passo você precisa verificar qual o caminho para a sua loja.
No meu exemplo: /var/www/vhosts/loja.com
Vamos abrir a pasta /var/www/vhosts:

cd /var/www/vhosts

Agora que vamos salvar toda a pasta loja.com:

tar -cvf backup_loja.tar loja.com

Agora já temos o backup dos arquivos, precisamos fazer um backup do banco de dados. Você precisa saber qual o nome do banco de dados que você utiliza, para nosso exemplo será: loja_magento.
Execute o seguinte comando (será necessário informar a senha):

mysqldump -u root -p loja_magento > loja_magentosql

Agora que já temos o backup vamos atualizar o Magento. Primeiro abra a pasta onde está o Magento.

cd /var/www/vhosts/loja.com

Nosso segundo passo é baixar o Magento 1.9:

wget http://www.magentocommerce.com/downloads/assets/1.9.0.1/magento-1.9.0.1.tar.gz
tar xvf magento-1.9.0.1.tar.gz

Vamos abrir o arquivo .htaccess e alterar o máximo de memória que pode utilizar e o tempo máximo de execução do PHP. Tome muito cuidado com os números, diminue ou aumente caso seja necessário.

php_value memory_limit 2048M
php_value max_execution_time 90000

Agora vamos limpar todos os caches e atualizar o apache/nginx. Caso você utilize Ubuntu/Debian utilize apache2, no exemplo utilizamos CentOS/RHEL. Caso tenha Varnish adicione mais uma linha com o Varnish.

rm -rf var/cache/* var/session/* var/locks/* var/full_page_cache/* tmp/*
rm -rf downloader/pearlib/cache/* downloader/pearlib/download/*
service httpd restart

Vamos remover agora a pasta downloader e app/design/frontend/base. Vamos remover estes arquivos para não ter problemas com arquivos que foram alterados. Execute o comando:

rm -rf downloader
rm -rf app/design/frontend/base

O nosso próximo passo é copiar os estas pastas que removemos direto da versão nova, execute o comando:

cp -a magento/downloader .
cp -a magento/app/design/frontend/base/ app/design/frontend/

Vamos utilizar também o arquivo mage da versão nova. Execute:

cp magento/mage .
chmod 755 ./mage

Antes de fazer a atualização nós precisamos ter certeza que o Connect está configurado para Stable. Execute o comando:

./mage config-set preferred_state stable

Vamos agora copiar todos os arquivos do Magento novo. Para ter certeza que todos os arquivos foram copiados, vamos rodar o mesmo comando 3 vezes. Execute o seguinte comando:

for i in {1..3}; do yes | cp -Rf magento/* .; done

Agora vamos fazer a atualização utilizando mage, para isso execute o comando:

./mage mage-setup .
./mage sync --force
./mage install http://connect20.magentocommerce.com/community Mage_All_Latest --force

Depois de terminar a atualização vamos limpar o cache e alterar a permissão do arquivo mage. Execute:

rm -rf var/cache/* var/session/* var/locks/* var/full_page_cache/* tmp/*
rm -rf downloader/pearlib/cache/* downloader/pearlib/download/*
chmod 755 mage

Vamos atualizar  os índices da loja. Você poderá encontrar um erro neste passo, ignore e continue com o tutorial. Execute o comando:

php shell/indexer.php reindexall

Calma que ainda falta. Vamos agora atualizar os módulos que não são de base do Magento.

./mage upgrade-all --force

Agora que terminamos de atualizar os arquivos do Magento, vamos setar as permissões corretas:

find . -type f -exec chmod 644 {} \;
find . -type d -exec chmod 777 {} \;
chmod 755 mage
chmod o+w var var/.htaccess app/etc
chmod -R o+w media
chmod -R 777 var/package var/locks var/report var/export downloader

Lembre de atualizar a permissão de usuário na pasta do Magento. Neste exemplo utilizarei o apache (CentOS/RHEL). Para Ubuntu/Debian utilize www-data:

chown -R apache:apache *

Pronto, a atualização dos ARQUIVOS está completa. Falta atualizar o banco de dados. Esta parte é automatizada, você somente precisa abrir a sua loja.
Logo você verá que a loja não irá abrir, fica somente lendo e nada. Isto significa que o banco de dados está sendo atualizado. Este passo pode demorar VÁRIOS minutos e você terá que ser paciente.
Recomendo que você vá ver TV, jogar algo, comer, o que seja. Para você ver se algo está acontecendo no seu banco de dados você pode executar o comando:

watch -n 5 mysqladmin -p processlist

Caso acontece algum erro, como aconteceu comigo, o erro irá aparecer na página inicial. Normalmente é alguma tabela no banco de dados que não existe, esta informação estará no erro. Nós precisamos criar esta tabela no banco de dados, mas precisamos saber qual a estrutura dela. Para isso acesse o seguinte site que contém todas as tabelas: http://www.magereverse.com/index/magento-sql-structure/version/1-7-0-2

Faça a busca pela tabela que está no erro e copie a parte referente à tabela. Agora utilizando algum sistema de administração do MySQL (phpMyAdmin) você pode criar a tabela necessária utilizando a informação que foi copiada.
Depois de criar a tabela você pode atualizar a página inicial de sua loja e você verá que a página irá ficar lendo novamente sem abrir. Caso a loja pare de funcionar, verifique no banco de dados se algo está acontecendo. Pode ser que o tempo máximo de execução do PHP tenha acabado.

Depois de ter sido atualizado você precisará remover alguns arquivos do Google Checkout devido à um erro que acontece ao abrir o admin, execute o comando abaixo:

rm -rf app/code/core/Mage/GoogleCheckout/etc/adminhtml.xml
rm -rf app/code/core/Mage/GoogleCheckout/etc/system.xml
rm -rf app/code/core/Mage/GoogleCheckout/etc/wsdl.xml
rm -rf app/code/core/Mage/GoogleCheckout/etc/wsi.xml

Vamos atualizar os índices novamente e desta vez não deve aparecer nenhum erro:

php shell/indexer.php reindexall

Sua loja já deve estar sem problemas para acessar e o admin também já deve estar funcionando. Mas logo no começo deste tutorial nós removemos a pasta app/design/frontend/base e vários módulos colocam seus arquivos aqui. Será necessário fazer o upload dos arquivos de seu módulo que vão aqui.

Este tutorial tem como fonte: http://duntuk.com/magento-upgrade

Espero que este tutorial tenha lhe ajudado à atualizar a sua loja.

Até a próxima!

]]>
<![CDATA[Mantendo Seu Admin Seguro]]>http://blog.magebr.com/pt/mantendo-seu-admin-seguro/5ea39e7c01ef706c1698d81cTue, 27 Mar 2018 23:36:00 GMTEscolha uma senha forte.Mantendo Seu Admin Seguro

Uma senha forte pode lhe proteger de invasores, lembre-se de utilizar uma senha com vários caracteres, misturando minúscula com maiscúla, número e pontuação. Recomendo utilizar o site Strong Password Generator: http://strongpasswordgenerator.com/
Nada de utilizar senhas contendo datas, nomes conhecidos ou palavras fáceis.

Não utilize sua senha em outro local.

É recomendado ter uma senha diferente para cada local, nunca repita a sua senha em outros locais.

Não utilize o caminho /admin padrão.

Por padrão o Magento utiliza o caminho /admin para acessar o painel administrativo. Este caminho é muito fácil e será sempre utilizado por hackers ou bots para acessar seu admin.
Você pode alterar esse caminho abrindo o arquivo app/etc/local.xml e localizando:

<frontName><![CDATA[admin]]></frontName>

Altere para um nome onde somente você conhece, algo como: paineladministrativosupersecreto

Utilize e-mails não conhecidos.

O Magento possui uma função de recuperar a senha por email e isso pode ser muito útil e também muito perigoso.
Caso seu email tenha sido comprometido, o seu admin pode estar em grande risco também.
Ao cadastrar contas com acesso ao painel administrativo utilize emails que não serão reconhecidos facilmente ou que não estejam publicados no site ou outro local.

SSL.

Utilize conexão segura no painel administrativo, será mais uma segurança contra ataques.
Para ativar SSL no admin, vá em SISTEMA –> Configuração –> WEB –> HTTPS.
Em BASE URL verifique que o link esteja com https.
Agora marque sim na opção USAR HTTPS NO ADMIN.

Autenticação com dois fatores.

Infelizmente hoje ter um admin seguro não é suficiente. Para melhorar ainda mais a proteção de seu admin, utilize a autenticação com dois fatores.
Esse tipo de autenticação irá solicitar um código somente após você colocar sua senha corretamente. Normalmente este código é gerado por um aplicativo em seu celular ou um aparelho que gera um token.
Alguns módulos:

  1. Rublon – Gratuito: http://www.magentocommerce.com/magento-connect/rublon.html
  2. Two-Factor Authentication – Pago: http://www.magentocommerce.com/magento-connect/two-factor-authentication.html

Há outras formas de segurança como limitar o acesso por IP, mas resolvi não colocar neste tutorial já que os IPs no Brasil normalmente mudam com frequência e isso pode trazer um problema para quem quiser acessar o painel administrativo de uma outra localidade.
Caso você tenha mais outras dicas não deixe de comentar abaixo.

Até a próxima!

]]>
<![CDATA[Apresentar Quantidade de Produtos Disponíveis]]>http://blog.magebr.com/pt/apresentar-quantidade-de-produtos-disponiveis/5ea39e2c01ef706c1698d807Tue, 27 Mar 2018 23:21:00 GMT

Para produtos simples, há algumas maneiras de fazer isso e vou mostrar 2.

A primeira forma seria alterando o arquivo app/design/frontend/base/default/template/catalog/product/view/type/default.phtml

Procure por:

<p class="availability in-stock"><?php echo $this->__('Availability:') ?> <span><?php echo $this->__('In stock') ?></span></p>

Altere para:

<p class="availability in-stock"><?php echo $this->__('Availability: ') ?><?=(int)Mage::getModel('cataloginventory/stock_item')->loadByProduct($_product)->getQty()?><?php echo $this->__(' em estoque.') ?></p>

Ficará assim:

Apresentar Quantidade de Produtos Disponíveis

A segunda forma seria alterando o mesmo arquivo.

Vamos buscar por:

<p class="availability in−stock">__('Availability:') ?> __('In stock') ?>

Logo abaixo adicionamos o código:

<div class="divider"></div>
<div class="inventory-qty">
<!--inv-qty--><br />
<?php<br />
$__manStock = $_product->getStockItem()->getManageStock();<br />
$__invAmt = (int)Mage::getModel('cataloginventory/stock_item')->loadByProduct($_product)->getQty();<br />
if ($__manStock > 0)<br />
{<br />
echo $this->__("Somente $__invAmt disponiveis em estoque");<br />
}<br />
?>
</div>

Ficará assim:

Apresentar Quantidade de Produtos Disponíveis

Já para alterar arquivos agrupados precisa alterar mais alguns códigos, mas nada muito complicado.
Vamos alterar o arquivo: app/design/frontend/base/default/template/catalog/product/view/type/grouped.phtml

Procure por:

<td class="a-center">
<?php if ($_item->isSaleable()) : ?><br />
<input name="super_group[<?php echo $_item->getId() ?>]" value="<?php echo $_item->getQty()*1 ?>" type="text" class="input-text qty" /><br />
<?php else: ?><br />
<?php echo $this->__('Out of stock.') ?><br />
<?php endif; ?>
</td>

Agora insira acima deste código o seguinto código:

<td class="a-center">
<?php if($_product->isSaleable()): ?><br />
<?= (int) Mage::getModel('cataloginventory/stock_item')->loadByProduct($_item)->getQty()?><br />
<?php else: ?><?php echo $this->__('Out of Stock') ?><?php endif; ?>
</td>

Por útimo procure por:

<thead>
<tr>
<th><?php echo $this->__('Product Name') ?></th>
<th class="a-right"><?php echo $this->__('Price') ?></th>
<p> <?php if ($_product->isSaleable()): ?></p>
<th class="a-center"><?php echo $this->__('Qty') ?></th>
<p> <?php endif; ?><br />
</tr>
</thead>

E altere por:

<thead>
<tr>
<th><?php echo $this->__('Product Name') ?></th>
<th class="a-left"><?php echo $this->__('Price') ?></th>
<th class="a-right"><?php echo $this->__('Availability') ?></th>
<p> <?php if ($_product->isSaleable()): ?></p>
<th class="a-center"><?php echo $this->__('Qty') ?></th>
<p> <?php endif; ?><br />
</tr>
</thead>

Pronto, agora os produtos agrupados ficarão assim:

Apresentar Quantidade de Produtos Disponíveis

Espero que tenham gostado do tutorial e deixem seus comentários!

]]>