<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Felipe Elia</title>
    <description>The latest articles on DEV Community by Felipe Elia (@felipeelia).</description>
    <link>https://dev.to/felipeelia</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F242712%2Ffeaab5e6-9d89-4cfc-aceb-4f9d2e70aa9d.jpg</url>
      <title>DEV Community: Felipe Elia</title>
      <link>https://dev.to/felipeelia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/felipeelia"/>
    <language>en</language>
    <item>
      <title>Updating my profile on GitHub</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Sun, 27 Aug 2023 19:30:13 +0000</pubDate>
      <link>https://dev.to/felipeelia/updating-my-profile-on-github-3bmm</link>
      <guid>https://dev.to/felipeelia/updating-my-profile-on-github-3bmm</guid>
      <description>&lt;p&gt;It's been a while since it's possible to customize your &lt;a href="https://felipeelia.dev/tags/github/" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; profile. I never had any ideas to do something cool, but after watching &lt;a href="https://www.youtube.com/watch?v=G-EGDH50hGE" rel="noopener noreferrer"&gt;this video&lt;/a&gt;, I used &lt;a href="https://rahuldkjain.github.io/gh-profile-readme-generator/" rel="noopener noreferrer"&gt;this tool&lt;/a&gt; to update &lt;a href="https://github.com/felipeelia/" rel="noreferrer noopener"&gt;my GitHub Profile&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/08/github-profile-felipeelia.png" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F08%2Fgithub-profile-felipeelia-1024x748.png" alt=""&gt;&lt;/a&gt; My updated GitHub profile&lt;/p&gt;

&lt;p&gt;The process is quite simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a repository with the same name as your username. In my case, it was &lt;a href="https://github.com/felipeelia/felipeelia" rel="noreferrer noopener"&gt;https://github.com/felipeelia/felipeelia&lt;/a&gt;;&lt;/li&gt;



&lt;li&gt; Open the tool, fill in the necessary fields and generate the README.md file;&lt;/li&gt;



&lt;li&gt; Push the file to your repository.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There is a &lt;a href="https://felipeelia.dev/tags/github-actions/" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt; that keeps the blog posts list updated, but the reference in the tool is outdated. I already sent a &lt;a href="https://github.com/rahuldkjain/github-profile-readme-generator/pull/749" rel="noopener noreferrer"&gt;Pull Request with the necessary change&lt;/a&gt;, but you can copy it from my repository and adjust it as needed.&lt;/p&gt;

&lt;p&gt;Here are some profiles I used as a reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/aachal28" rel="noopener noreferrer"&gt;https://github.com/aachal28&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/fabdul88" rel="noreferrer noopener"&gt;https://github.com/fabdul88&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/gautamkrishnar" rel="noreferrer noopener"&gt;https://github.com/gautamkrishnar&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/zadilkhwaja" rel="noopener noreferrer"&gt;https://github.com/zadilkhwaja&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;a href="https://github.com/sl4ureano" rel="noopener noreferrer"&gt;https://github.com/sl4ureano&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Finally, I created an account on &lt;a href="https://ko-fi.com/felipeelia" rel="noopener noreferrer"&gt;Ko-Fi&lt;/a&gt; and added that &lt;em&gt;Buy me a coffee&lt;/em&gt; button. I don't expect any donations, but if anyone ever wants to, there's an easy way to do it.&lt;/p&gt;

</description>
      <category>github</category>
      <category>git</category>
      <category>socialmedia</category>
    </item>
    <item>
      <title>Remote work: positions and hiring process</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Fri, 17 Feb 2023 17:57:10 +0000</pubDate>
      <link>https://dev.to/felipeelia/remote-work-positions-and-hiring-process-4j7h</link>
      <guid>https://dev.to/felipeelia/remote-work-positions-and-hiring-process-4j7h</guid>
      <description>&lt;p&gt;Looking for a remote work opportunity but don't know how the hiring process is? In this post, I share some tips on &lt;strong&gt;places where to find remote work positions and things about the hiring process&lt;/strong&gt; I wish someone told me before.&lt;/p&gt;

&lt;p&gt;This post is the second part of a &lt;strong&gt;series about remote work and international jobs&lt;/strong&gt;. Check the other post link in the list below. I'll update the list as I publish new texts but don't forget to follow me!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://felipeelia.dev/international-jobs-does-my-english-need-to-be-perfect/" rel="noopener noreferrer"&gt;International Jobs: Does my English need to be perfect?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Where to find job opportunities&lt;/h2&gt;

&lt;p&gt;My content focus is WordPress, so here is a list of places I recommend to find &lt;strong&gt;positions related to WP&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The company you like&lt;/strong&gt;&lt;br&gt;This should be the obvious starting point. If there is a company you like or admire, you should try it first.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://10up.com/careers/" rel="noreferrer noopener"&gt;&lt;strong&gt;10up&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;10up is the company I currently work for. I learned and continue to learn a lot of different things there and I can say the experience change my life and career in different aspects. And it is hiring!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WordPress Newsletters&lt;/strong&gt;&lt;br&gt;There are a lot of WordPress-related newsletters out there and some of them have a section just to list open opportunities. The newsletters I like to read are &lt;a href="https://masterwp.com/" rel="noreferrer noopener"&gt;MasterWP&lt;/a&gt;, &lt;a href="https://wpowls.co/" rel="noreferrer noopener"&gt;WP Owls&lt;/a&gt;, and &lt;a href="https://poststatus.com/" rel="noreferrer noopener"&gt;Post Status&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.codeable.io/" rel="noreferrer noopener"&gt;&lt;strong&gt;Codeable&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;Codeable is not a development agency but a freelancer platform. I got many projects there and I recommend it.&lt;/p&gt;

&lt;p&gt;Codeable works around all the common pitfalls of these platforms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The final value of a project is not the cheapest but an average of all values. The client can't see how much each developer wants to charge, so the dev is selected by the messages exchange rather than price.&lt;/li&gt;



&lt;li&gt;It has (or at least had) a selection process, assuring good quality from all the freelancers.&lt;/li&gt;



&lt;li&gt;Payment is done to Codeable before the project starts and is forwarded to the developer only when it is done, making it a safe place for all parts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Codeable served as an entry door to the international market and I think it is an excellent option for those who want to start working internationally.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have a good place that lists WordPress-related jobs opportunities, leave a suggestion here in the comments!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;It is normal not to be called&lt;/h2&gt;

&lt;p&gt;Don't be afraid to fail. I tried an internship at &lt;a href="https://automattic.com/" rel="noreferrer noopener"&gt;Automattic&lt;/a&gt; twice, and got to the final phases but wasn't accepted. Don't give up and keep studying and trying to get that job!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember: &lt;strong&gt;You don't lose anything by hearing a NO.&lt;/strong&gt; Everybody was rejected at least once.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;It is time to send your CV!&lt;/h2&gt;

&lt;p&gt;After you found the company you want, it is time to get noticed. In this step, you will need two things: an updated resumé (CV) and a cover letter.&lt;/p&gt;

&lt;h3&gt;But before...&lt;/h3&gt;

&lt;p&gt;We can have a post about hard and soft skills (what do you think?) but know that although tech knowledge is needed, &lt;strong&gt;companies look for people that communicate well and want to learn&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It is also worth remembering that first impressions are key, so update everything you have online that is related to work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Update your LinkedIn, GitHub, and WordPress.org profiles!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;CV: concise and with what will draw attention&lt;/h3&gt;

&lt;p&gt;Your resumé just needs one or two pages, with your main experiences and knowledge (courses, certificates, etc.) There are free templates on the internet with modern visuals and pretty easy to fill out.&lt;/p&gt;

&lt;p&gt;See an example below (with the link):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gdoc.io/resume-templates/job-resume-free-google-docs-template" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-7.png" alt="" width="800" height="500"&gt;&lt;/a&gt;Modern and concise CV Template&lt;/p&gt;

&lt;h3&gt;&lt;em&gt;Cover Letter&lt;/em&gt;&lt;/h3&gt;

&lt;p&gt;This part can be new for a lot of people. It is &lt;strong&gt;just a page of text with a few paragraphs&lt;/strong&gt;. It should be something specific to the position, so do not send the same cover letter to different places.&lt;/p&gt;

&lt;p&gt;There are the items you need to include in your &lt;em&gt;cover letter&lt;/em&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your personal info (name, location, email, mobile, etc.);&lt;/li&gt;



&lt;li&gt;Your connection with the company, where you saw the position;&lt;/li&gt;



&lt;li&gt;History, mainly what you are currently doing;&lt;/li&gt;



&lt;li&gt;Why you should be hired.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are a lot of cover letter examples on the web. TIP: The best examples you will find searching on Google Images, not simple text.&lt;/p&gt;

&lt;h2&gt;Interviews&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;If they want to interview you, congratulations!&lt;/strong&gt; It is common to see hiring processes with lots of interviews, made by different sectors. Celebrate each step!&lt;/p&gt;

&lt;p&gt;It is time to pay attention to a few things:&lt;/p&gt;

&lt;h3&gt;Review your equipment: earphones, microphone, and internet connection&lt;/h3&gt;

&lt;p&gt;Before each interview, make sure your earphones, headsets, and/or microphone are working properly, without any noise or similar. If your wifi is unstable, it is worth using a cable, even if that means sitting near the router for a day or having a long cable across the house for a few hours.&lt;/p&gt;

&lt;h3&gt;Prior preparation is fundamental&lt;/h3&gt;

&lt;p&gt;Some questions are classics and you should be prepared beforehand. The basics “Tell us about you”, “which was the most difficult project you worked on?”, “what do you like and dislike in WordPress?” should be on the tip of your tongue.&lt;/p&gt;

&lt;h3&gt;Know the company and the job position&lt;/h3&gt;

&lt;p&gt;Showing interest is key in any relationship, of any nature. Knowing a little about the company and the position will demonstrate this interest, giving you some points with the interviewer.&lt;/p&gt;

&lt;h3&gt;If possible, search for the interviewer&lt;/h3&gt;

&lt;p&gt;This can help a lot if the interview is in English and you are not so confident. It may sound a bit of a &lt;em&gt;stalker&lt;/em&gt;, but finding a talk or video with the interviewer can give you time to learn their accent and familiarize yourself with the way they talk.&lt;/p&gt;

&lt;h3&gt;An interview is not an interrogatory&lt;/h3&gt;

&lt;p&gt;You can (and should) ask questions. That also demonstrates interest. An idea is to ask about advantages offered by the company, like days off, paid courses, and equipment.&lt;/p&gt;

&lt;h3&gt;
&lt;em&gt;Live Coding&lt;/em&gt;: think out loud&lt;/h3&gt;

&lt;p&gt;If the hiring process has a &lt;em&gt;live coding&lt;/em&gt; step (those sessions when you need to write code with someone else looking over your shoulder), remember to think out loud.&lt;/p&gt;

&lt;p&gt;The final code is not always so important. &lt;em&gt;How&lt;/em&gt; you are thinking and &lt;em&gt;which steps you are trying to make&lt;/em&gt; are what really matters.&lt;/p&gt;

&lt;p&gt;Imagine a math test where the final result is obviously relevant but the accounts you made to get to the result also matter.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this post, we saw some places that offer WordPress-related career opportunities. We also saw it is normal to not get the job on the first attempt. &lt;strong&gt;Do not give up!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We also saw some &lt;strong&gt;essential things in a good CV and cover letter&lt;/strong&gt;, as well as important points to keep in mind about what companies are really looking for.&lt;/p&gt;

&lt;p&gt;Lastly, we saw that &lt;strong&gt;prior planning can be essential in a good interview&lt;/strong&gt;. Prepare your space and mind can make you feel more comfortable during the interview&lt;/p&gt;

</description>
      <category>bolt</category>
      <category>ai</category>
      <category>codenewbie</category>
      <category>productivity</category>
    </item>
    <item>
      <title>International Jobs: Does my English need to be perfect?</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Fri, 10 Feb 2023 12:08:16 +0000</pubDate>
      <link>https://dev.to/felipeelia/international-jobs-does-my-english-need-to-be-perfect-1kb1</link>
      <guid>https://dev.to/felipeelia/international-jobs-does-my-english-need-to-be-perfect-1kb1</guid>
      <description>&lt;p&gt;November last year I gave a talk in WordCamp São Paulo about remote work and finally the text version is here! If you speak Portuguese, &lt;a href="https://www.youtube.com/live/scpc5z5hGQQ?feature=share&amp;amp;t=2987" rel="noreferrer noopener"&gt;the talk is available on YouTube&lt;/a&gt;. There is also a &lt;a href="https://felipeelia.com.br/vagas-internacionais-meu-ingles-precisa-ser-perfeito/" rel="noreferrer noopener"&gt;pt_BR version of this text.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That was a long talk, so I'm going to publish the text in parts. &lt;strong&gt;Do not forget to follow me here to get notifications about the next posts&lt;/strong&gt;, okay?&lt;/p&gt;

&lt;h2&gt;Does my English need to be perfect?&lt;/h2&gt;

&lt;p&gt;This is people's first question when we talk about working for an international company. If you think you need to speak English like a native to get a job, that is a barrier that only exists in your mind.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Understand and be understood&lt;/strong&gt; are the only things you really need.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is really it. If you can understand someone speaking in English and if people can understand you speaking English even with your accent (&lt;strong&gt;everybody&lt;/strong&gt; has an accent) you are ready.&lt;/p&gt;

&lt;h2&gt;Nothing replaces a course&lt;/h2&gt;

&lt;p&gt;Every once in a while we hear about some superheroes that learned how to speak English all by themselves. That is not the reality for most people though. There are at least two things you most likely have only by attending a course:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Writing practice&lt;/strong&gt; - Only by practicing you will learn some irregular verbs' past forms (&lt;em&gt;think &amp;gt; thought&lt;/em&gt;), how do you spell some words, etc.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Grammar&lt;/strong&gt; - Knowing the basics will make your life easier when you don't understand a word but get the overall context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don't need a 15-year course, that is not my point. You do need to be sure you have the basics of writing and grammar structures.&lt;/p&gt;

&lt;h2&gt;Movies, TV shows, games, and code &lt;em&gt;lives&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;I was super afraid of entering into a meeting and not understanding a word people were saying. I started watching TV shows and YouTube videos. First with English subtitles, then with no subtitles at all. This exercise helped me and it still helps me a lot.&lt;/p&gt;

&lt;p&gt;Code lives on Twitch also help a lot. There you will &lt;em&gt;hear&lt;/em&gt; some jargons that you only &lt;em&gt;read&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here are some examples that worked for me. At the time I gave the talk I was watching Andor, today I'd say &lt;em&gt;The Last of Us&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.disneyplus.com/pt-br/series/star-wars-andor/3xsQKWG00GL5" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage.png" alt="" width="414" height="231"&gt;&lt;/a&gt;Andor (Disney+)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/@gameranxTV" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-3.png" alt="" width="414" height="231"&gt;&lt;/a&gt;Gameranx (YouTube)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/@SirZanny" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-2.png" alt="" width="414" height="231"&gt;&lt;/a&gt;Zanny (YouTube)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.twitch.tv/ryanwelchercodes" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-4.png" alt="" width="414" height="231"&gt;&lt;/a&gt;RyanWelcherCodes (Twitch)&lt;/p&gt;

&lt;h2&gt;&lt;strong&gt;Real life&lt;/strong&gt;&lt;/h2&gt;

&lt;p&gt;Courses, YouTube videos, TV shows... none of that really prepares you for real life. In real life you will need to deal with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Acronyms and expressions&lt;/strong&gt; - These folks really love acronyms. &lt;em&gt;EOD&lt;/em&gt;, &lt;em&gt;ASAP&lt;/em&gt;, and AFAIK are some of them but you will see a lot of new ones when you start. Expressions like &lt;em&gt;Ballpark estimates&lt;/em&gt; are also part of this item.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Broken audio&lt;/strong&gt; - In a movie everybody hears each other without any noise. In real life the video freezes, the audio breaks up, and more. Expressions like &lt;em&gt;Do you mind saying that again?&lt;/em&gt; or &lt;em&gt;You broke up a bit&lt;/em&gt; I only heard after attending meetings.&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Accents&lt;/strong&gt; - I am lucky to be part of a very plural team. We have American, German, Indian, Hungarian, Mexican, and more. Sometimes it is hard to get one or two explanations but instead of faking you understood, it is better to say &lt;em&gt;I’m not sure I follow…&lt;/em&gt; and ask them to explain it in a different way. This happens more than people imagine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I don't know how courses outside Brazil work but here we learn something like &lt;em&gt;How are you? I'm fine, thanks, and you?&lt;/em&gt; In real life, no one really uses that. Pay attention to others and adapt.&lt;/p&gt;

&lt;h2&gt;When I joined the company, I almost gave up!&lt;/h2&gt;

&lt;p&gt;I've been part of 10up for 3 years now but I almost quit in my first weeks. We have a daily standup and it was nearly impossible for me to understand one of my colleagues.&lt;/p&gt;

&lt;p&gt;I brought that to my leadership team and they told me it was normal and that I would get used to it. I really got used to it after a while.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;It can be hard in the beginning. &lt;strong&gt;Do not give up!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here is a tip: &lt;strong&gt;always be frank, and never pretend you understood&lt;/strong&gt;. Companies really value people who know how to communicate well and (as weird as it may sound) part of good communication is saying when something needs to be explained in a different way.&lt;/p&gt;

&lt;h2&gt;Tools&lt;/h2&gt;

&lt;p&gt;In addition to Google Translate, there are at least two tools that help me a lot on a daily bases and I think it is worth sharing with you:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-5.png" alt="" width="506" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Grammarly&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grammarly is a service that helps while writing in English. I use it as a browser extension and it helps me with things like the image.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F02%2Fimage-6.png" alt="" width="773" height="348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Google “define:ACRONYM”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As I said, acronyms are very common in English. When I see a new one that I don't know yet, I search for &lt;code&gt;define:ACRONYM&lt;/code&gt; in Google and usually, the first result is already enough.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this first post of the series, we saw that &lt;strong&gt;understanding and being understood&lt;/strong&gt; is the level of English you need to have to try an international job.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Practice in writing and grammar knowledge is essential&lt;/strong&gt;, so a course is recommended. It doesn't need to be a 10 years course, but a structured study with a few months at least.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Watching something you like&lt;/strong&gt; as YouTube videos, TV shows, and movies help a lot but with subtitles in English or no subtitle at all. Code lives are also interesting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nothing replaces real-life experience.&lt;/strong&gt; Expressions and trivial problems are not represented in movies and series, so be prepared to learn a lot at the beginning.&lt;/p&gt;

&lt;p&gt;I also told a little about my bumpy start and how I almost quit in the first weeks. &lt;strong&gt;It is important to persist, it is worth it!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Lastly, we saw some &lt;strong&gt;tools&lt;/strong&gt; you will want to keep near you when communicating in a different language.&lt;/p&gt;








&lt;p&gt;This was just the first part! &lt;strong&gt;Follow me here and on social networks&lt;/strong&gt; to be updated about part 2.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>latam</category>
    </item>
    <item>
      <title>WordPress Health Status and the new Report Parser Tool</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Thu, 02 Feb 2023 10:00:00 +0000</pubDate>
      <link>https://dev.to/felipeelia/wordpress-health-status-and-the-new-report-parser-tool-50ck</link>
      <guid>https://dev.to/felipeelia/wordpress-health-status-and-the-new-report-parser-tool-50ck</guid>
      <description>&lt;p&gt;What is your WordPress version? And PHP? How many posts do you have?  Status reports gather all those information in a single place. Just copy and paste, and answer all the support questions at once. But what do we do when the report is not easy to read?&lt;/p&gt;

&lt;h2&gt;Asking the same questions over and over again&lt;/h2&gt;

&lt;p&gt;Asking or answering the same questions is too boring, everybody agrees. Everybody also agrees that &lt;strong&gt;the solution for repeated tasks is automation&lt;/strong&gt;. If the system knows all the answers, why not get them directly from the source, saving everybody's time? Status or system reports are meant for this.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the system knows all the answers, why not get them directly from the source, saving everybody's time?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Status report pages are already common in the WordPress ecosystem. &lt;strong&gt;Go to a specific page, click on a button, and paste it into a ticket&lt;/strong&gt;. The report isn't always that legible but I've created a tool to help with that.&lt;/p&gt;

&lt;h2&gt;The &lt;em&gt;&lt;a href="https://felipeelia.dev/report-parser/" rel="noopener noreferrer"&gt;Report Parser&lt;/a&gt;&lt;/em&gt; Tool&lt;/h2&gt;

&lt;p&gt;Status pages are divided into sections containing lists of key-value pairs. In WordPress, for example, we have the "WordPress" section, and some keys are "Version", "Site Language", etc. The copy-and-paste report shared with support follows the same format but &lt;strong&gt;it gets really hard to read when the value is too big&lt;/strong&gt;. Imagine a JSON object, for example.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;&lt;a href="https://felipeelia.dev/report-parser/" rel="noopener noreferrer"&gt;Report Parser&lt;/a&gt;&lt;/em&gt; helps with that problem: just paste the report into the textarea and it is possible to see it formatted with collapsible sections.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.dev/report-parser/" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Freport-parser-screenshot-911x1024.png" alt="" width="800" height="899"&gt;&lt;/a&gt;Screenshot of the &lt;em&gt;Report Parser&lt;/em&gt; Tool&lt;/p&gt;

&lt;p&gt;The idea to create the tool came after we added the new &lt;em&gt;Status Report&lt;/em&gt; page to &lt;a href="https://github.com/10up/ElasticPress/releases/tag/4.4.0" rel="noreferrer noopener"&gt;ElasticPress 4.4.0&lt;/a&gt;. There we aggregate answers for lots of common support questions, like the last failed Elasticsearch queries.&lt;/p&gt;

&lt;p&gt;With these Elasticsearch queries, I noticed &lt;strong&gt;a problem: common lists are easy to read but bigger JSON objects are not&lt;/strong&gt;. The tool serves as a way back: keep both the easiness of copy-and-paste reports and readability for support teams.&lt;/p&gt;

&lt;h2&gt;WordPress Site Health Info&lt;/h2&gt;

&lt;p&gt;WordPress 5.2 added a new page with Site Health Info, previously only available via the &lt;a href="https://wordpress.org/plugins/health-check/" rel="noreferrer noopener"&gt;Health Check plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/wordpress-site-health-info.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fwordpress-site-health-info.png" alt="" width="800" height="641"&gt;&lt;/a&gt;Screenshot of WordPress' Site Health Info&lt;/p&gt;

&lt;h3&gt;The Report Format&lt;/h3&gt;

&lt;p&gt;After you click on the &lt;em&gt;Copy site info to clipboard&lt;/em&gt; button, a report like the one below will be available to be pasted:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;### wp-core ###

version: 6.1.1
site_language: pt_BR
user_language: pt_BR
....

### wp-dropins (2) ###

advanced-cache.php: true
object-cache.php: true&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As you must have noticed, the basic structure is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;### &amp;lt;section_name&amp;gt; ###

key_1: &amp;lt;value_1&amp;gt;
key_2: &amp;lt;value_2&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Report Parser&lt;/em&gt; gets that format and transforms it back into collapsible sections and formatted tables.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;How to add your own sections to the &lt;em&gt;WordPress Site Health Info&lt;/em&gt; page&lt;/h3&gt;

&lt;p&gt;Well, as we are already here, let's see &lt;strong&gt;how simple it is to add a new section with your plugin or theme info&lt;/strong&gt;. All we need is to use the &lt;code&gt;&lt;a href="https://developer.wordpress.org/reference/hooks/debug_information/" rel="noreferrer noopener"&gt;debug_information&lt;/a&gt;&lt;/code&gt; filter, returning the array with a new index.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function my_custom_health_info_section( $debug_info ) {
    $debug_info['section_slug'] = [
        'label'  =&amp;gt; __( 'My Custom Health Info Section', 'textdomain' ),
        'fields' =&amp;gt; [
            'field_slug_1' =&amp;gt; [
                'label' =&amp;gt; __( 'Label 1', 'textdomain' ),
                'value' =&amp;gt; 'value 1',
            ],
            'field_slug_2' =&amp;gt; [
                'label' =&amp;gt; __( 'Label 2', 'textdomain' ),
                'value' =&amp;gt; 'value 2',
            ],
        ],
    ];

    return $debug_info;
}
add_filter( 'debug_information', 'my_custom_health_info_section' );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The code above creates a new section, like the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/new-wordpress-health-tools-section.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fnew-wordpress-health-tools-section.png" alt="" width="800" height="190"&gt;&lt;/a&gt;Our new section in WordPress Site Health Info&lt;/p&gt;

&lt;p&gt;In the copy-and-paste report, our section looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;### section_slug ###

field_slug_1: value 1
field_slug_2: value 2&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Status reports in plugins&lt;/h2&gt;

&lt;p&gt;Some plugins have their own status reports. That happens because they were created before WordPress added this functionality or because &lt;strong&gt;their reports are so complex that they don't fit into the WordPress structure&lt;/strong&gt;, which has only one level of hierarchy.&lt;/p&gt;

&lt;h3&gt;WooCommerce&lt;/h3&gt;

&lt;p&gt;WooCommerce's System Status is available under &lt;em&gt;WooCommerce &amp;gt; Status&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/woocommerce-status-page.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fwoocommerce-status-page-1024x513.png" alt="" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Some sections stand out there, like Database, Settings, and WooCommerce pages, super specific to the plugin. &lt;strong&gt;In WooCommerce, the copy-and-paste report stays visible&lt;/strong&gt;, different from almost all other solutions available.&lt;/p&gt;

&lt;h3&gt;Gravity Forms&lt;/h3&gt;

&lt;p&gt;Gravity Forms' System Report is available by going to &lt;em&gt;Forms &amp;gt; System Status&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/gravity-forms-status-page.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fgravity-forms-status-page-1024x389.png" alt="" width="800" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to a section called Gravity Forms, the section Database (pretty much like WooCommerce's) &lt;strong&gt;lists all the plugin custom tables&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;ElasticPress&lt;/h3&gt;

&lt;p&gt;The ElasticPress &lt;em&gt;Status Report&lt;/em&gt; page was born from a support need and was inspired by several existent solutions. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/elasticpress-status-report.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Felasticpress-status-report-1024x804.png" alt="" width="800" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to extremely specific sections like &lt;em&gt;Indexable Content&lt;/em&gt;, &lt;em&gt;Elasticsearch Indices&lt;/em&gt;, and &lt;em&gt;Last Sync&lt;/em&gt;, the ElasticPress report has another difference: &lt;strong&gt;an extra hierarchy level&lt;/strong&gt;. There we have the &lt;em&gt;WordPress&lt;/em&gt; section, for example, with the &lt;em&gt;WordPress Environment&lt;/em&gt; and &lt;em&gt;Server Environment&lt;/em&gt; subsections.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this post we saw a new tool called &lt;a href="https://felipeelia.dev/report-parser/" rel="noopener noreferrer"&gt;&lt;strong&gt;Report Parser&lt;/strong&gt;&lt;/a&gt;, available here in the blog, to &lt;strong&gt;better visualize&lt;/strong&gt; WordPress and its plugins' Status Reports.&lt;/p&gt;

&lt;p&gt;We had a look at the Health Info from WordPress itself, the standard format used in all reports, and how it is possible to &lt;strong&gt;add your own section&lt;/strong&gt; to WP's report.&lt;/p&gt;

&lt;p&gt;At last, we saw &lt;strong&gt;some plugins that have their own reports&lt;/strong&gt; like WooCommerce, Gravity Forms, and ElasticPress.&lt;/p&gt;








&lt;p&gt;Don't forget to share the post and &lt;strong&gt;subscribe to the newsletter&lt;/strong&gt;!&lt;/p&gt;

</description>
      <category>cryptocurrency</category>
      <category>crypto</category>
      <category>web3</category>
      <category>bitcoin</category>
    </item>
    <item>
      <title>FTP No More: Deploying WordPress sites with GitHub Actions</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Fri, 27 Jan 2023 13:45:38 +0000</pubDate>
      <link>https://dev.to/felipeelia/ftp-no-more-deploying-wordpress-sites-with-github-actions-11c6</link>
      <guid>https://dev.to/felipeelia/ftp-no-more-deploying-wordpress-sites-with-github-actions-11c6</guid>
      <description>&lt;p&gt;Do you still use FileZilla to send files one by one to the server? It is time to change! After reading this post all you will need is to push a file to a GitHub repository and it will be automatically sent to your server.&lt;/p&gt;

&lt;h2&gt;If you are in a hurry... that is fine!&lt;/h2&gt;

&lt;p&gt;There is no problem if you are in a hurry. In summary, this is what we are going to do:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
Create an SSH Keys pair to connect to your server;&lt;/li&gt;

&lt;li&gt;
Create the &lt;code&gt;DEPLOY_SSH_HOST&lt;/code&gt;, &lt;code&gt;DEPLOY_SSH_USER&lt;/code&gt;, and &lt;code&gt;DEPLOY_SSH_KEY&lt;/code&gt; secrets in GitHub;&lt;/li&gt;

&lt;li&gt;
Create the &lt;code&gt;bin/rsync-excludes.txt&lt;/code&gt; file in your repository;&lt;/li&gt;

&lt;li&gt;
Create the &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; file in your repository;&lt;/li&gt;

&lt;li&gt;Make any changes in the &lt;code&gt;trunk&lt;/code&gt; branch.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;If this post helps you, don't forget to share it!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;What you need&lt;/h2&gt;

&lt;p&gt;The list of things you need for this post is quite simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;SSH Acess to your server&lt;/strong&gt;: Available in almost all host providers nowadays;&lt;/li&gt;

&lt;li&gt;
&lt;strong&gt;A GitHub repository&lt;/strong&gt;: Free and unlimited, including private ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Don't forget to back up your files before you continue. If something goes wrong you will have a way to revert it.&lt;/p&gt;

&lt;h2&gt;What the GitHub Action will do&lt;/h2&gt;

&lt;p&gt;Basically, when a file in a certain branch is updated, &lt;strong&gt;a GitHub Action will connect to your server via SSH and send the files&lt;/strong&gt; using the &lt;code&gt;rsync&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-3.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fimage-3.png" alt="" width="780" height="211"&gt;&lt;/a&gt;The green ✓ means an Action was executed successfully.&lt;/p&gt;

&lt;h2 id="ssh-access"&gt;SSH Access&lt;/h2&gt;

&lt;p&gt;Your GitHub Action will need to connect to your server via SSH (Secure SHell) to send the files. To make that possible, &lt;strong&gt;we will create a new pair of SSH keys and configure the server to accept it&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;1. Create a pair of SSH keys&lt;/h3&gt;

&lt;p&gt;The cryptography used by the SSH protocol uses &lt;strong&gt;two keys: a public and a private&lt;/strong&gt;. So your GitHub Action can send the files to your server, you will need a new pair of keys. Although possible, I do not recommend using the same key you use on your computer.&lt;/p&gt;

&lt;p&gt;The command to create a new key is the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh-keygen -t ed25519 -C "user@domain"&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ssh-keygen&lt;/code&gt;: The command itself;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;-t ed25519&lt;/code&gt;: The algorithm used in the file creation;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;-C "user@domain"&lt;/code&gt;: It does not need to be a real email. It is only used to differentiate keys, as a comment. Something like &lt;code&gt;deploy@mysite.com&lt;/code&gt; is enough.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The command will ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;A password&lt;/em&gt;: leave it empty to make the process easier;&lt;/li&gt;

&lt;li&gt;
&lt;em&gt;A filename&lt;/em&gt;: do not use the default, put something like &lt;code&gt;deploy&lt;/code&gt; or the project name. Do not add any extensions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-5.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fimage-5-1024x494.png" alt="" width="800" height="385"&gt;&lt;/a&gt;The &lt;code&gt;ssh-keygen&lt;/code&gt; command and its return&lt;/p&gt;

&lt;h3&gt;2. Authorize the key to connect to your server&lt;/h3&gt;

&lt;p&gt;Each hosting provider handles this in a different way. In services that provide some sort of dashboard, it can be in My Account &amp;gt; SSH or similar.&lt;/p&gt;

&lt;p&gt;On Cloudways, for example, the SSH keys are handled per application. In the &lt;em&gt;Access Details&lt;/em&gt; section, it is possible to manage the keys under &lt;em&gt;Application Credentials&lt;/em&gt;. (Cloudways also offers a &lt;em&gt;Deployment Via Git&lt;/em&gt; option that we are not covering here.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/cloudways-ssh.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fcloudways-ssh-1024x477.png" alt="" width="800" height="372"&gt;&lt;/a&gt;Cloudways Application Management dashboard&lt;/p&gt;

&lt;p&gt;In the image we have arrows pointing to three elements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Public IP&lt;/em&gt;: This will be used as the host in our setting. In many cases, it is the website domain.&lt;/li&gt;

&lt;li&gt;
&lt;em&gt;Username&lt;/em&gt;: Cloudways has a different &lt;em&gt;username&lt;/em&gt; per application. Some hosts use the same username for dashboard and SSH accesses.&lt;/li&gt;

&lt;li&gt;
&lt;em&gt;SSH Keys&lt;/em&gt;: This is the place where it is possible to set new keys for this application. There, you can provide the public key (&lt;code&gt;file.pub&lt;/code&gt;) of the pair we've generated.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;3. Test the SSH key (Optional)&lt;/h3&gt;

&lt;p&gt;You can use your computer to test the access using the new key. For that, all you have to do is call:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh -i &amp;lt;private-key-filepath&amp;gt; &amp;lt;user&amp;gt;@&amp;lt;server&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;private-key-filepath&amp;gt;&lt;/code&gt;: The path to the private key file (without&lt;code&gt;.pub&lt;/code&gt;) in your computer;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;&amp;lt;user&amp;gt;@&amp;lt;server&amp;gt;&lt;/code&gt;: It can change depending on the provider. For that screenshot from Cloudways, it would be &lt;code&gt;appname_ssh@12.34.567.890&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If we would use the key generated in our example, the call would look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh -i /home/elia/.ssh/exemplopost appname_ssh@12.34.567.890&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you had everything right, you will see the server terminal on your computer.&lt;/p&gt;

&lt;h2 id="github-actions"&gt;GitHub Actions&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/features/actions" rel="noreferrer noopener"&gt;GitHub Actions&lt;/a&gt; is GitHub's automation tool.&lt;/strong&gt; In summary, GitHub will analyze any &lt;code&gt;.yml&lt;/code&gt; file in the &lt;code&gt;.github/workflows&lt;/code&gt; folder of your repository and try to execute it every time something happens in your repo.&lt;/p&gt;

&lt;p&gt;In our case, we will create a file named &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt;. You can name it as you want but you need to keep the &lt;code&gt;.yml&lt;/code&gt; extension and the file location.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;ATTENTION: .yml files do not allow &lt;em&gt;tabs&lt;/em&gt;, only &lt;em&gt;spaces &lt;/em&gt;(2 or 4).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; file contents will be as follows:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;name: Deploy

env:
  SSH_USER: $`{{ secrets.DEPLOY_SSH_USER }}`
  SSH_HOST: $`{{ secrets.DEPLOY_SSH_HOST }}`

on:
  push:
    branches:
      - trunk

jobs:
  deploy_cloudways:
    name: Deploy to Cloudways
    runs-on: ubuntu-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: Configure SSH
      run: |
        mkdir -p ~/.ssh/
        echo "$SSH_KEY" &amp;gt; ~/.ssh/deploy.key
        chmod 600 ~/.ssh/deploy.key
        cat &amp;gt;&amp;gt;~/.ssh/config &amp;lt;&amp;lt;END
        Host cloudways
          HostName $SSH_HOST
          User $SSH_USER
          IdentityFile ~/.ssh/deploy.key
          StrictHostKeyChecking no
        END
      env:
        SSH_KEY: $`{{ secrets.DEPLOY_SSH_KEY }}`

    - name: Send files
      run: "rsync --delete -avO $`{{ env.RSYNC_FLAGS }}` --exclude-from=$`{{ env.EXCLUDES }}` ./ $`{{ env.SSH_USER }}`@$`{{ env.SSH_HOST }}`:$`{{ env.DESTINATION }}`"
      env:
        RSYNC_FLAGS: '' #--dry-run
        EXCLUDES: bin/rsync-excludes.txt
        SSH_HOST: cloudways
        DESTINATION: "~/public_html/wp-content/"
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Workflow name&lt;/h3&gt;

&lt;p&gt;The first line of our file simply gives a name to our &lt;em&gt;&lt;a href="https://docs.github.com/pt/actions/learn-github-actions/understanding-github-actions#fluxos-de-trabalho" rel="noreferrer noopener"&gt;workflow&lt;/a&gt;&lt;/em&gt;. The name is used just for display purposes and does not interfere with the automation functionality.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;name: Deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Secrets for GitHub Action&lt;/h3&gt;

&lt;p&gt;The second section of our file configures environment variables to be shared across some &lt;em&gt;steps &lt;/em&gt;further up.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;env:
  SSH_USER: $`{{ secrets.DEPLOY_SSH_USER }}`
  SSH_HOST: $`{{ secrets.DEPLOY_SSH_HOST }}`&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As the description of our workflow is made in a file visible to anyone with read access in the repository, GitHub provides a way to create secrets, editable only by administrators of the repo or organization.&lt;/p&gt;

&lt;h4 id="how-to-create-a-secret-in-github-actions"&gt;How to create a secret in GitHub Actions&lt;/h4&gt;

&lt;p&gt;Let's remember the SSH access command we previously used to test:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh -i &amp;lt;private-key-filepath&amp;gt; &amp;lt;user&amp;gt;@&amp;lt;server&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;With that command in mind, access your repository, and go to Settings &amp;gt; Secrets and Variables &amp;gt; Actions. &lt;strong&gt;We will create three secrets&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DEPLOY_SSH_KEY&lt;/code&gt;: The &lt;strong&gt;content&lt;/strong&gt; of the private key you created.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;DEPLOY_SSH_USER&lt;/code&gt;: What you used as &lt;code&gt;&amp;lt;user&amp;gt;&lt;/code&gt;;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;DEPLOY_SSH_HOST&lt;/code&gt;: What you used as &lt;code&gt;&amp;lt;server&amp;gt;&lt;/code&gt;;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that &lt;code&gt;DEPLOY_SSH_KEY&lt;/code&gt; is different from the others: we are using the &lt;em&gt;file path &lt;/em&gt;in the command but the secret has the &lt;em&gt;content&lt;/em&gt; of the file. This happens because we will create the file during the &lt;em&gt;action&lt;/em&gt; execution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-4.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fimage-4-1024x449.png" alt="" width="800" height="350"&gt;&lt;/a&gt;Form to create a secret in GitHub&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;DEPLOY_SSH_KEY&lt;/code&gt; secret is not in this &lt;code&gt;env&lt;/code&gt; section on purpose. It will be used later.&lt;/p&gt;

&lt;h3&gt;Triggers and Events&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;on:
  push:
    branches:
      - trunk&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The content of this section is quite self-explanatory: the steps in this file will only be executed if the &lt;code&gt;trunk&lt;/code&gt; branch changes.&lt;/p&gt;

&lt;p&gt;Instead of &lt;code&gt;push&lt;/code&gt;, it could be &lt;code&gt;pull_request&lt;/code&gt; or &lt;code&gt;schedule&lt;/code&gt;, for example. &lt;/p&gt;

&lt;h3&gt;Jobs&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;jobs&lt;/code&gt; section is a set of steps to be executed. Our &lt;em&gt;workflow &lt;/em&gt;file has only one &lt;em&gt;job&lt;/em&gt; but it is possible to have more than one. Different &lt;em&gt;jobs&lt;/em&gt; run in parallel.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;jobs:
  deploy_cloudways:
    name: Deploy to Cloudways
    runs-on: ubuntu-latest&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;deploy_cloudways&lt;/code&gt; string could be any slug, the same is valid for &lt;code&gt;Deploy to Cloudways&lt;/code&gt;. These are just names.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ubuntu-latest&lt;/code&gt; string specifies under which OS the job will run. It is possible to use different Linux, Windows, and macOS versions. See the &lt;a href="https://docs.github.com/pt/actions/using-workflows/workflow-syntax-for-github-actions#escolhendo-executores-hospedados-em-github" rel="noreferrer noopener"&gt;full list&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Steps&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Steps&lt;/em&gt; are the parts that make a &lt;em&gt;job&lt;/em&gt; and they are executed in order.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    steps:
    - name: Checkout
      uses: actions/checkout@v2&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our first step is the repository &lt;em&gt;checkout&lt;/em&gt;. Usually, this will be the very first step of all the &lt;em&gt;workflows&lt;/em&gt; you will see out there. It simply brings the repository content to the &lt;em&gt;action&lt;/em&gt;'s environment.&lt;/p&gt;

&lt;h3&gt;SSH Configuration&lt;/h3&gt;

&lt;p&gt;This section configures SSH of the machine running our action in GitHub.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    - name: Configure SSH
      run: |
        mkdir -p ~/.ssh/
        echo "$SSH_KEY" &amp;gt; ~/.ssh/deploy.key
        chmod 600 ~/.ssh/deploy.key
        cat &amp;gt;&amp;gt;~/.ssh/config &amp;lt;&amp;lt;END
        Host cloudways
          HostName $SSH_HOST
          User $SSH_USER
          IdentityFile ~/.ssh/deploy.key
          StrictHostKeyChecking no
        END
      env:
        SSH_KEY: $`{{ secrets.DEPLOY_SSH_KEY }}`&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mkdir -p ~/.ssh/&lt;/code&gt;: Creates the &lt;code&gt;.ssh&lt;/code&gt; directory inside the &lt;code&gt;$HOME&lt;/code&gt; folder of GH's machine.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;echo "$SSH_KEY" &amp;gt; ~/.ssh/deploy.key&lt;/code&gt;: Puts the content of the &lt;code&gt;SSH_KEY&lt;/code&gt; variable inside the &lt;code&gt;deploy.key&lt;/code&gt; file.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;chmod 600 ~/.ssh/deploy.key&lt;/code&gt;: Configures the permissions of the &lt;code&gt;deploy.key&lt;/code&gt; file. In this case, &lt;code&gt;600&lt;/code&gt; means the owner can read and write on it but no one else is able to access it.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;cat &amp;gt;&amp;gt;~/.ssh/config &amp;lt;&amp;lt;END&lt;/code&gt;: What you see between &lt;code&gt;&amp;lt;&amp;lt;END&lt;/code&gt; and &lt;code&gt;END&lt;/code&gt; will be inserted in the &lt;code&gt;config&lt;/code&gt; file of the &lt;code&gt;.ssh&lt;/code&gt; directory.&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Host cloudways&lt;/code&gt;: Creates a name for the following configuration. When calling SSH passing &lt;code&gt;cloudways&lt;/code&gt;, the data below will be used;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;HostName $SSH_HOST&lt;/code&gt;: The server address. If you remember what we talked about the &lt;code&gt;env&lt;/code&gt; section, this variable will receive the value of the &lt;code&gt;DEPLOY_SSH_HOST&lt;/code&gt; secret;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;User $SSH_USER&lt;/code&gt;: Similar to &lt;code&gt;HostName&lt;/code&gt; but applied to the user;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;IdentityFile ~/.ssh/deploy.key&lt;/code&gt;: Specifies the path of the key to be used when connecting to  &lt;code&gt;Host&lt;/code&gt;;&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;StrictHostKeyChecking no&lt;/code&gt;: Skips the server's identity verification with the &lt;code&gt;known_hosts&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;lt;!-- /wp:list --&amp;gt;&lt;/p&gt;


&lt;/li&gt;


&amp;lt;!-- /wp:list-item --&amp;gt;&lt;/ul&gt;

&lt;p&gt;Down below, we can see an &lt;code&gt;env&lt;/code&gt; section, similar to that global one (declared at the beginning of our file.) Note that in this case the variable is created only for this step. Here we are passing the content of the &lt;code&gt;DEPLOY_SSH_KEY&lt;/code&gt; secret to an environment variable called &lt;code&gt;SSH_KEY&lt;/code&gt;. The content of this variable will be added to the &lt;code&gt;deploy.key&lt;/code&gt; file, as we saw.&lt;/p&gt;

&lt;h3&gt;Send files with &lt;code&gt;rsync&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;In the last step, we will finally change the content of the target server. For this, we will use the &lt;code&gt;rsync&lt;/code&gt; command, which synchronizes the files from one place to another. Here, the files in GitHub's machine (origin) with the files in your server (target.)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;    - name: Send files
      run: "rsync --delete -avO $`{{ env.RSYNC_FLAGS }}` --exclude-from=$`{{ env.EXCLUDES }}` ./ $`{{ env.SSH_USER }}`@$`{{ env.SSH_HOST }}`:$`{{ env.DESTINATION }}`"
      env:
        RSYNC_FLAGS: '' #--dry-run
        EXCLUDES: bin/rsync-excludes.txt
        SSH_HOST: cloudways
        DESTINATION: "~/public_html/wp-content/"&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the &lt;code&gt;rsync&lt;/code&gt; command is something new to you, let's give a deeper look into each one of the parameters we are calling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--delete&lt;/code&gt;: If a file does not exist in the origin, also delete it in the target.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;-avO&lt;/code&gt;: &lt;code&gt;-a&lt;/code&gt; is to sync all files, folders, and symbolic links preserving their permissions. That &lt;code&gt;v&lt;/code&gt; is for &lt;code&gt;verbose&lt;/code&gt;, i.e., outputs to the terminal the list of changes being made. That &lt;code&gt;O&lt;/code&gt; (an uppercase "o") tells &lt;code&gt;rsync&lt;/code&gt; to not worry about folders' modification dates.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;$`{{ env.RSYNC_FLAGS }}`&lt;/code&gt;: As you can imagine, this will be replaced with the content of &lt;code&gt;RSYNC_FLAGS&lt;/code&gt;, configured a couple of lines below. Usually, it doesn't receive anything but you can pass &lt;code&gt;--dry-run&lt;/code&gt;, for example, to simulate what the command would do without changing anything in the real world.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;--exclude-from=$`{{ env.EXCLUDES }}`&lt;/code&gt;: You can pass the path of a file containing the list of everything that should be ignored by &lt;code&gt;rsync&lt;/code&gt;. Check the next section to know more about it.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;./&lt;/code&gt;: The path (in the origin) that needs to be synced.&lt;/li&gt;

&lt;li&gt;
&lt;code&gt;$`{{ env.SSH_USER }}`@$`{{ env.SSH_HOST }}`:$`{{ env.DESTINATION }}`&lt;/code&gt;: The target path. The last part will be replaced by the folder in the target server. In our case, the repository only contains the &lt;code&gt;wp-content&lt;/code&gt; files and the website is located in the &lt;code&gt;$HOME/public_html&lt;/code&gt; folder on the server. In your case, the folder can be elsewhere, like &lt;code&gt;/var/www/html&lt;/code&gt;. Access your server or search in your host configurations to get where in the server your website files are located.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id="about-exclusions-and-rsync"&gt;About exclusions and &lt;code&gt;rsync&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;In the previous example, we are using a file called &lt;code&gt;rsync-excludes.txt&lt;/code&gt; located in the &lt;code&gt;bin&lt;/code&gt; folder of the repository. &lt;strong&gt;This file has a list of files and folders that should be ignored&lt;/strong&gt; by the &lt;code&gt;rsync&lt;/code&gt; command. For example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;*.gitignore
*.gitmodules
*.git
*.gitkeep
*.github

/bin
*rsync-excludes.txt

/uploads
/upgrade
/themes/index.php
/plugins/index.php&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instead of using &lt;code&gt;--exclude-from=&amp;lt;file&amp;gt;&lt;/code&gt; you can change the &lt;code&gt;rsync&lt;/code&gt; call and use &lt;code&gt;--exclude .git --exclude README.md&lt;/code&gt;, for example.&lt;/p&gt;

&lt;h2&gt;Doing more with GitHub Actions&lt;/h2&gt;

&lt;p&gt;If you want, it is also possible to call commands like &lt;code&gt;&lt;a href="https://felipeelia.com.br/o-que-e-o-composer-do-php/" rel="noopener noreferrer"&gt;composer install&lt;/a&gt;&lt;/code&gt; or &lt;code&gt;&lt;a href="https://www.youtube.com/watch?v=tFqsmNrWW0M" rel="noreferrer noopener"&gt;npm install&lt;/a&gt;&lt;/code&gt; during the process, so you don't have to version 3rd party files in your repo. In addition to that, the process can also be triggered by a &lt;a href="https://felipeelia.dev/is-labeling-pull-requests-messages-a-good-idea/" rel="noopener noreferrer"&gt;Pull Request&lt;/a&gt; creation or time periods (hourly, daily, etc.)&lt;/p&gt;

&lt;p&gt;For real examples, give a look at &lt;a href="https://github.com/10up/ElasticPress/blob/develop/.github/workflows/cypress-tests.yml" rel="noreferrer noopener"&gt;the ElasticPress repository&lt;/a&gt;. There you will see actions executed daily, automated tests, deployments to WordPress.org, and more.&lt;/p&gt;

&lt;h2&gt;Why you should not use SFTP anymore&lt;/h2&gt;

&lt;p&gt;Firstly, &lt;strong&gt;you should be using a version control system like &lt;a href="https://felipeelia.dev/categorias/git-en/" rel="noreferrer noopener"&gt;git&lt;/a&gt;, even if you work alone.&lt;/strong&gt; Versioning your projects in a git repo will give you control of your changes and a backup. It is also a &lt;a href="https://felipeelia.dev/categorias/career/" rel="noopener noreferrer"&gt;requirement in most jobs&lt;/a&gt; nowadays.&lt;/p&gt;

&lt;p&gt;The process described here has several advantages over the old method of sending file by file using a program like FileZilla, for example. My favorite is that you'll be sending only the files that were changed, making it all &lt;strong&gt;easier and faster&lt;/strong&gt;. We also avoid having different people updating the same file and overwriting changes one from the other.&lt;/p&gt;

&lt;p&gt;I used GitHub and GitHub Actions in this post but there are several alternatives available if you want. The process of sending files to a server through a repository is called &lt;em&gt;Continuous Delivery&lt;/em&gt; and is part of the &lt;em&gt;Continuous Integration&lt;/em&gt;, &lt;em&gt;Delivery, &lt;/em&gt;and &lt;em&gt;Deployment&lt;/em&gt; topic, also known as &lt;strong&gt;CI/CD&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;In this post, we saw a method to send files to a server from a git repository.&lt;/p&gt;

&lt;p&gt;To access the server, an SSH key pair is needed. The public key is stored in the server, the private key is stored as a secret in GitHub.&lt;/p&gt;

&lt;p&gt;We also saw how easy it is to create a &lt;em&gt;workflow&lt;/em&gt; in GitHub: we just need to create a &lt;code&gt;.yml&lt;/code&gt; file in the &lt;code&gt;.github/workflows&lt;/code&gt; folder. To restrict access to sensitive information we can use GitHub secrets.&lt;/p&gt;

&lt;p&gt;The sync between files is made through the &lt;code&gt;rsync&lt;/code&gt; command, which accepts several parameters. It is also possible to exclude files from the sync through different ways: a list in a file with the &lt;code&gt;--exclude-from&lt;/code&gt; parameter or several &lt;code&gt;--exclude&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This post is just a glimpse of what is possible with GitHub Actions. It is also possible to use &lt;a href="https://felipeelia.com.br/o-que-e-o-composer-do-php/" rel="noopener noreferrer"&gt;Composer&lt;/a&gt; and &lt;a href="https://www.youtube.com/watch?v=tFqsmNrWW0M" rel="noreferrer noopener"&gt;NPM&lt;/a&gt; during the process and much more.&lt;/p&gt;

&lt;p&gt;Lastly, we saw why this deployment method is much better than sending individual files via SFTP.&lt;/p&gt;




&lt;p&gt;Don't forget to share the post and leave a comment!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>discuss</category>
      <category>privacy</category>
      <category>diversity</category>
    </item>
    <item>
      <title>Deprecated code in Open Source (with WordPress functions)</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Wed, 18 Jan 2023 11:57:43 +0000</pubDate>
      <link>https://dev.to/felipeelia/deprecated-code-in-open-source-with-wordpress-functions-1oml</link>
      <guid>https://dev.to/felipeelia/deprecated-code-in-open-source-with-wordpress-functions-1oml</guid>
      <description>&lt;p&gt;Keeping a codebase organized always requires some changes: functions, files, structures, everything someday needs a new name or place. &lt;strong&gt;How do we make a change without breaking anything?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open-source codebases come with several advantages but some specific challenges. Different from a service that simply provides a more strict API, like a REST API, for example, &lt;strong&gt;others can call almost anything in your code&lt;/strong&gt;. That said, you must be cautious even while renaming the simplest function.&lt;/p&gt;

&lt;p&gt;Although all this can sound painful, it is not. &lt;strong&gt;Keeping your codebase organized is worth it!&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id="faca-a-limpeza-em-fases"&gt;Make the change in phases&lt;/h2&gt;

&lt;p&gt;Simply renaming the function is not a good idea: any solution depending on it will suddenly break. You need to &lt;strong&gt;warn that action will be needed&lt;/strong&gt; and, after enough time, really implement the new solution.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To define what and when needs to be changed, we can use &lt;strong&gt;Semantic Versioning&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="versionamento-semantico"&gt;&lt;strong&gt;Semantic Versioning&lt;/strong&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://semver.org/" rel="noreferrer noopener nofollow"&gt;Semantic Versioning&lt;/a&gt; gives meaning to the numbers of a software version&lt;/strong&gt;, aligning expectations of what can happen in each new release.&lt;/p&gt;

&lt;p&gt;The following table summarizes what would be the &lt;strong&gt;major, minor, and patch&lt;/strong&gt; version number of a software in its 2.4.3 release, in addition to what we could expect from the upcoming 2.4.4, 2.5.0, or 3.0.0 releases.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Major &lt;/strong&gt;(&lt;strong&gt;2.&lt;/strong&gt;4.3)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Minor&lt;/strong&gt; (2.&lt;strong&gt;4.&lt;/strong&gt;3)&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Patch &lt;/strong&gt;(2.4.&lt;strong&gt;3&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Changes that &lt;strong&gt;do break&lt;/strong&gt; backward compatibility&lt;/td&gt;
&lt;td&gt;New features that &lt;strong&gt;do not break &lt;/strong&gt;backward compatibility&lt;/td&gt;
&lt;td&gt;Bug fixes only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Updating to &lt;strong&gt;version 3.0.0&lt;/strong&gt; requires attention, as the current solution can break&lt;/td&gt;
&lt;td&gt;Updating to &lt;strong&gt;version 2.5.0&lt;/strong&gt; means that everything continues to work but with some new functionality&lt;/td&gt;
&lt;td&gt;Updating to &lt;strong&gt;version 2.4.4&lt;/strong&gt; means some bugs were fixed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;h3 id="exemplo-pratico"&gt;Practical Example&lt;/h3&gt;

&lt;p&gt;Keeping both the function rename example and our 2.4.3 version in mind, let's see how we could plan that out. Let's split the process into some steps and define their release versions.&lt;/p&gt;

&lt;h4 id="versao-2-5-0-implementar-o-codigo-novo-e-alterar-o-codigo-velho-sem-quebrar"&gt;Version 2.5.0: Implement new code and change the old code without breaking it&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Implement the new code.&lt;/strong&gt; It doesn't matter if it is a renamed function or a brand-new method, the new code needs to be there so people can do the switch;&lt;/li&gt;



&lt;li&gt;
&lt;strong&gt;Change the old code.&lt;/strong&gt; In case it is just a simple switch, the old code needs to become a wrapper of the new function with a warning about the (now) wrong usage;&lt;/li&gt;
&lt;/ol&gt;

&lt;pre&gt;&lt;code&gt;
function new_name( $parameter ) {
    // Do something
}

function old_name( $parameter ) {
    _deprecated_function( __FUNCTION__, '2.5.0', 'new_name' );
    new_name( $parameter );
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that calling &lt;code&gt;old_name()&lt;/code&gt; still works but a warning was added there saying that starting from version 2.5.0 &lt;code&gt;new_name()&lt;/code&gt; is the function that should be called.&lt;/p&gt;

&lt;h4 id="versao-3-0-0-remover-o-codigo-velho"&gt;Version 3.0.0: Remove the old code&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;After warning for long enough, you can remove the old code.&lt;/strong&gt; Attention: this removal is expected to happen in a &lt;em&gt;major&lt;/em&gt; version.&lt;/p&gt;

&lt;p&gt;You do not need to remove the code in the immediate following version, though. Depending on your user base and your release calendar you can wait for any major version, like 4.0.0 or 5.0.0, for example.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A project that just releases a major version per year can have a slightly different approach from a project that releases a major version per month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="arquivos-com-codigos-obsoletos"&gt;Move deprecated code into separate files&lt;/h3&gt;

&lt;p&gt;One of the intentions behind these changes is to keep your codebase clean and organized. With that in mind, keeping these functions in your main files can make you uncomfortable as things can actually look messier than before.&lt;/p&gt;

&lt;p&gt;Some development teams &lt;strong&gt;move these pieces of code to specific files&lt;/strong&gt;, named &lt;code&gt;deprecated.php&lt;/code&gt;, for example. In addition to a readability increase, this also helps when you need to identify which code can be removed while launching 3.0.0.&lt;/p&gt;

&lt;h2 id="quanto-mais-comunicacao-melhor"&gt;The more you communicate, the better&lt;/h2&gt;

&lt;p&gt;In the example above we called the &lt;code&gt;_deprecated_function()&lt;/code&gt; WordPress function but that will only have an effect if the &lt;code&gt;WP_DEBUG&lt;/code&gt; constant is set to true.&lt;/p&gt;

&lt;p&gt;Unfortunately, quite often these warnings are useless: in many cases, people are not paying any attention to logs. &lt;strong&gt;You also need to warn your users in an accessible and human-readable way.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Inform your users about important changes in all ways possible: logs warnings, items in your changelog, blog posts, and even social media if needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id="changelog-ou-registro-de-alteracoes"&gt;Changelog&lt;/h3&gt;

&lt;p&gt;The best place to communicate changes in your software is in its &lt;em&gt;changelog&lt;/em&gt;. In WordPress, this type of log is kept in a specific section of the &lt;em&gt;readme.txt&lt;/em&gt; file and is displayed on both the plugin page and in a modal inside the Dashboard.&lt;/p&gt;

&lt;p&gt;Using Akismet as an example, this is the link to see the next version's details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HAK11KAy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2023/01/image.png" alt="" width="800" height="177"&gt;&lt;/a&gt;Plugins list in WordPress's Dashboard. The yellow notice is delayed when there is a new version of the plugin.&lt;/p&gt;

&lt;p&gt;Clicking on the link will open a modal with the &lt;em&gt;changelog&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-1.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sRR4WNt4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2023/01/image-1.png" alt="" width="800" height="683"&gt;&lt;/a&gt;Modal with the plugin's changelog. Versions are usually ordered from the newest to the oldest.&lt;/p&gt;

&lt;p&gt;WordPress gets that information from the &lt;code&gt;== Changelog ==&lt;/code&gt; section of the readme.txt plugin's file, hosted in WP.org official repository:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/image-2.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--shgVjH10--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2023/01/image-2.png" alt="" width="800" height="238"&gt;&lt;/a&gt;&lt;a href="https://plugins.trac.wordpress.org/browser/akismet/tags/5.0.2/readme.txt" rel="noreferrer noopener nofollow"&gt;Akismet's readme.txt file&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, changelogs are divided into sections, separating what was added, changed, fixed, removed, and deprecated. An example of this division can be seen in both &lt;a href="https://github.com/10up/ElasticPress/releases/tag/4.4.1" rel="noreferrer noopener"&gt;ElasticPress's release notes&lt;/a&gt; and its changelog.&lt;/p&gt;

&lt;h3 id="funcoes-do-wordpress"&gt;WordPress Functions&lt;/h3&gt;

&lt;p&gt;WordPress has some functions that help to inform the usage of deprecated code. Here is the list:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;_deprecated_function( $function, $version, $replacement = '' )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This function is in the example we used before. &lt;strong&gt;A simple way to mark a function as deprecated.&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;apply_filters_deprecated( $hook_name, $args, $version, $replacement = '', $message = '' )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This and the next are wrappers for &lt;code&gt;_deprecated_hook()&lt;/code&gt;, which is not part of this list, as it should not be called directly. As the name says, this function &lt;strong&gt;applies a filter&lt;/strong&gt; but also informs it is deprecated and, if available, provides its proper replacement.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;do_action_deprecated( $hook_name, $args, $version, $replacement = '', $message = '' )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Similar to the last one but &lt;strong&gt;applied to an action&lt;/strong&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;_doing_it_wrong( $function, $message, $version )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Although not necessarily related to deprecated code, I'm adding &lt;code&gt;_doing_it_wrong()&lt;/code&gt; to the list as it can be super &lt;strong&gt;useful when the change requires more attention than a simple name change&lt;/strong&gt;.  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;_deprecated_argument( $function, $version, $message = '' )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As the name implies, this is for a &lt;strong&gt;change in an argument&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Although always related to an argument, there are a couple of different scenarios where this function can be used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A change in the expected value of an argument like &lt;code&gt;'blacklist_keys'&lt;/code&gt; that is now &lt;code&gt;'disallowed_keys'&lt;/code&gt;;&lt;/li&gt;



&lt;li&gt;An argument that does not exist anymore;&lt;/li&gt;



&lt;li&gt;An index of an array argument. Let's say, before &lt;code&gt;$args['cat']&lt;/code&gt; was expected but now it is &lt;code&gt;$args['taxonomy']&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;_deprecated_file( $file, $version, $replacement = '', $message = '' )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Marks an entire file as deprecated.&lt;/strong&gt; Usage examples are renamed files or files that are not needed anymore. The &lt;code&gt;wp-includes/class-json.php&lt;/code&gt; file calls that function, as since WP 5.3.0 the native PHP extension is required.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;_deprecated_constructor( $class, $version, $parent_class = '' )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is &lt;strong&gt;related to object constructors&lt;/strong&gt;. Years ago, constructors methods in PHP had their class name but since PHP 5.4 the recommended way is using the magic &lt;code&gt;__construct()&lt;/code&gt; method. Class name constructors are deprecated since PHP 7.0 and should not be used anymore.&lt;/p&gt;

&lt;h2 id="sobre-os-termos-em-portugues"&gt;Obsolete vs. deprecated&lt;/h2&gt;

&lt;p&gt;Each language has its own specificity. For Brazilian Portuguese, for example, we don't have a specific word for "deprecated". People quite often wrongly translate that as "depreciated." So, we use obsolete and deprecated interchangeably.&lt;/p&gt;

&lt;p&gt;In English, those two words refer to different states of the code: deprecated code is still functional and present, obsolete code usually doesn't work anymore, and/or was removed from the codebase.&lt;/p&gt;

&lt;h2 id="conclusao"&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Keeping your codebase clean and organized is essential. To make the needed changes and keep retro compatibility you need to plan the &lt;strong&gt;changes in phases&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic Versioning&lt;/strong&gt; can help you to plan which changes are shipped in which versions, so your users are not caught off guard.&lt;/p&gt;

&lt;p&gt;Communicating changes through your &lt;strong&gt;&lt;em&gt;changelogs&lt;/em&gt; &lt;/strong&gt;also brings more visibility to actions your users will need to take. Specific sections listing those changes help even more.&lt;/p&gt;

&lt;p&gt;We also saw some &lt;strong&gt;WordPress functions&lt;/strong&gt; that can help to inform changes in several different scenarios.&lt;/p&gt;

&lt;p&gt;Lastly, we saw how these terms can vary in different languages and the &lt;strong&gt;difference between deprecated and obsolete&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>wordpress</category>
      <category>php</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Is labeling Pull Requests messages a good idea?</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Sun, 08 Jan 2023 20:50:06 +0000</pubDate>
      <link>https://dev.to/felipeelia/is-labeling-pull-requests-messages-a-good-idea-5ai</link>
      <guid>https://dev.to/felipeelia/is-labeling-pull-requests-messages-a-good-idea-5ai</guid>
      <description>&lt;p&gt;Reviewing a Pull Request is always a challenge: how do we keep quality and code consistency while keeping developers motivated? &lt;strong&gt;Does labeling Pull Requests messages make things easier to interpret?&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;Recently, &lt;a href="https://twitter.com/felipe_elia/status/1611080113545674753" rel="noreferrer noopener"&gt;I tweeted about the https://conventionalcomments.org/ website&lt;/a&gt;. The idea is simple: every time you review a PR, &lt;strong&gt;your messages should start with a label&lt;/strong&gt;, making it clear which is the next expected step (if any.)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/felipe_elia/status/1611080113545674753" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Ftweet-about-conventional-comments-1.png" alt="" width="800" height="592"&gt;&lt;/a&gt;E aí, já me segue no &lt;a href="https://twitter.com/felipe_elia" rel="noreferrer noopener"&gt;Twitter&lt;/a&gt;?&lt;/p&gt;

&lt;h2&gt;What is a &lt;em&gt;Pull Request&lt;/em&gt; (or &lt;em&gt;Merge Request&lt;/em&gt;?)&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;A Pull Request&lt;/em&gt; is a request to add some code to the project's "official" code.&lt;/strong&gt; Depending on the tool, these requests can be called &lt;em&gt;Merge Requests&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;It goes like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Person A&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Writes some code for a specific change or addition&lt;/li&gt;

&lt;li&gt;Opens a PR describing what and why has been changed;&lt;/li&gt;
&lt;/ul&gt;




&lt;/li&gt;




&lt;li&gt;A revision and adequation process happens. Part of this process can depend on a &lt;strong&gt;Person B&lt;/strong&gt; review.&lt;/li&gt;




&lt;li&gt;The code is merged. &lt;/li&gt;


&lt;/ul&gt;

&lt;p&gt;This post refers to messages from &lt;strong&gt;Person B&lt;/strong&gt; to &lt;strong&gt;Person A&lt;/strong&gt; explaining the changes needed before the code can be merged.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER:&lt;/strong&gt; There is a lot of material about PR etiquette. This post does not cover this specific topic but I do recommend you to search about it. Although just vaguely related, I recommend you to watch &lt;a href="https://www.youtube.com/watch?v=jMpCF0Z623s" rel="noreferrer noopener"&gt;this video by Dave Farley&lt;/a&gt; about leadership and &lt;strong&gt;how important it is to allow people to solve problems in ways you would not do it.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Prefixes and labels: Agreements about the format&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://conventionalcomments.org/" rel="noreferrer noopener"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fconventional-comments-1024x437.png" alt="" width="800" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The website suggests the following format for revision comments on &lt;em&gt;Pull Requests&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&amp;lt;label&amp;gt; [decorations]: &amp;lt;subject&amp;gt;

[discussion]&lt;/pre&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;suggestion (test,if-minor)&lt;/strong&gt;: It looks like we're missing some unit test coverage that the cat disappears completely.&lt;/p&gt;



&lt;p&gt;I am not sure if this is a big problem or not. Would it be possible to add tests for that scenario before we merge this?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the example we have:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Label (Ex.: &lt;em&gt;suggestion&lt;/em&gt;):&lt;/strong&gt;&lt;br&gt;The &lt;em&gt;suggestion&lt;/em&gt; label indicates this is about a possible improvement. What and why should be changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decorators (Ex.: &lt;em&gt;test, if-minor&lt;/em&gt;):&lt;/strong&gt;&lt;br&gt;A quick way to expand the label meaning. The comment is about tests and the decision of whether it should block or not the merge is up to the PR author, depending on the size of the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Subject:&lt;/strong&gt;&lt;br&gt;The main message of the comment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discussion:&lt;/strong&gt;&lt;br&gt;It is not required but can help to further explain the subject.&lt;/p&gt;

&lt;p&gt;The website has very good suggestions for &lt;em&gt;labels &lt;/em&gt;and &lt;em&gt;decorators&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;Two highlights: &lt;em&gt;nitpick &lt;/em&gt;and &lt;em&gt;praise&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;From the entire list, there are two that I found very interesting: &lt;em&gt;&lt;strong&gt;nitpick&lt;/strong&gt; &lt;/em&gt;and &lt;strong&gt;&lt;em&gt;praise&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;nitpick&lt;/strong&gt; label is a good way to say "This is not wrong but I would do this differently". I recommend you to pay attention and not overuse this but this label can be a good way to share knowledge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2023/01/conventional-comments-nitpick.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2023%2F01%2Fconventional-comments-nitpick-1024x154.png" alt="" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;&lt;b&gt;praise&lt;/b&gt;&lt;/em&gt; label is for compliments. This is one way to &lt;strong&gt;recognize a good, creative, and/or elegant solution&lt;/strong&gt;. As each comment creates a thread, the team can agree that the author can "resolve" it right after reading it.&lt;/p&gt;








&lt;p&gt;What do you think about this? Share your thoughts in the comments section below or via &lt;a href="https://linktr.ee/felipe.elia" rel="noreferrer noopener"&gt;social networks&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Will PHP 7.2 be the minimum required version for WP 6.2?</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Sun, 18 Dec 2022 21:23:21 +0000</pubDate>
      <link>https://dev.to/felipeelia/will-php-72-be-the-minimum-required-version-for-wp-62-826</link>
      <guid>https://dev.to/felipeelia/will-php-72-be-the-minimum-required-version-for-wp-62-826</guid>
      <description>&lt;p&gt;Yes, this is real! It seems that &lt;strong&gt;starting from WordPress 6.2 the minimum PHP version required by WP will be 7.2&lt;/strong&gt;. The last change in that aspect of the software was made in May 2019, for WordPress 5.2. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/12/meme-gatsy.jpg" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ffelipeelia.com.br%2Fwp-content%2Fuploads%2F2022%2F12%2Fmeme-gatsy.jpg" alt="" width="600" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The update did not happen before because the team set 5% as the maximum threshold of version usage. According to &lt;a href="https://core.trac.wordpress.org/ticket/57345" rel="noreferrer noopener"&gt;this ticket&lt;/a&gt;, PHP 5.6 usage finally dropped below that. As PHP doesn't have version 6 and versions 7.0 and 7.1 have usage numbers even lower, the minimum version would be bumped to PHP 7.2. The numbers are also available on the &lt;a href="https://wordpress.org/about/stats/" rel="noreferrer noopener"&gt;Stats page of WP.org&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;As of 17 Dec 2022 [...]:&lt;br&gt;&lt;br&gt;PHP 5.6 is at 4.99% of all WordPress sites&lt;br&gt;PHP 7.0 is at 2.68%&lt;br&gt;PHP 7.1 is at 1.82%&lt;/p&gt;
&lt;cite&gt;&lt;a href="https://core.trac.wordpress.org/ticket/57345" rel="noreferrer noopener"&gt;https://core.trac.wordpress.org/ticket/57345&lt;/a&gt;&lt;/cite&gt;
&lt;/blockquote&gt;

&lt;h2&gt;WordPress and PHP's timeline&lt;/h2&gt;

&lt;p&gt;To increase backward compatibility, WordPress adopts a strict policy regarding minimum PHP versions. PHP 5.2, for example, had its final version released in January 2011 but it was supported by WP until 2019.&lt;/p&gt;

&lt;p&gt;PHP 5.6 reached its &lt;a href="https://www.php.net/eol.php" rel="noreferrer noopener"&gt;end of life&lt;/a&gt; in December 2018 and today, 4 years later, it is still the minimum required version by WordPress. If the change really happens, we will be still behind: &lt;strong&gt;PHP 7.2 saw its last version released in November 2020&lt;/strong&gt;, two years ago.&lt;/p&gt;

&lt;p&gt;Out of curiosity, while I write this post, the oldest version &lt;a href="https://www.php.net/supported-versions.php" rel="noreferrer noopener"&gt;still receiving updates&lt;/a&gt; is PHP 8.0, with end-of-life planned for November 2023. The latest version, 8.2, was released this month and will receive security updates until December 2025.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;PHP End Of Life&lt;/th&gt;
&lt;th&gt;End of Support By WP&lt;/th&gt;
&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PHP 5.2&lt;/td&gt;
&lt;td&gt;01/2011&lt;/td&gt;
&lt;td&gt;05/2019 (WP 5.2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP 5.6&lt;/td&gt;
&lt;td&gt;12/2018&lt;/td&gt;
&lt;td&gt;??/2023 (WP 6.2)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP 7.2&lt;/td&gt;
&lt;td&gt;11/2020&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PHP 8.0 (current version)&lt;/td&gt;
&lt;td&gt;11/2023&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;What the PHP version changes for WordPress&lt;/h2&gt;

&lt;p&gt;Beyond &lt;strong&gt;improvements in security and speed&lt;/strong&gt;, changing the PHP version also makes available a set of new features, modernizing the codebase and decreasing the chances of bugs.&lt;/p&gt;

&lt;p&gt;You can see the full list of features that would be available in these three links: &lt;a href="https://www.php.net/manual/en/migration70.new-features.php" rel="noreferrer noopener"&gt;PHP 7.0&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/migration71.new-features.php" rel="noreferrer noopener"&gt;PHP 7.1&lt;/a&gt;, and &lt;a href="https://www.php.net/manual/en/migration72.new-features.php" rel="noreferrer noopener"&gt;PHP 7.2&lt;/a&gt;. Below you can see just &lt;strong&gt;some examples&lt;/strong&gt; of what we would get just setting PHP 7.0 as the minimum:&lt;/p&gt;

&lt;h3&gt;Return type declarations&lt;/h3&gt;

&lt;p&gt;Since PHP 7.0 it is possible to declare the type returned by a function or method:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function example( array ...$arrays ): array {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Although it is common in some other languages, type declarations (for parameters and return) can be something new to some.&lt;/p&gt;

&lt;p&gt;The biggest advantage of this feature is &lt;strong&gt;static analysis of code&lt;/strong&gt;: even without executing the code, it is possible to identify if &lt;code&gt;example()&lt;/code&gt; is being called without expecting an &lt;em&gt;array&lt;/em&gt;. If that is the case, the error can be detected and fixed before any other test is executed.&lt;/p&gt;

&lt;p&gt;The majority of IDEs already have that function built in nowadays.&lt;/p&gt;

&lt;h3&gt;Null coalescing operator (??)&lt;/h3&gt;

&lt;p&gt;Instead of writing&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$username = isset( $_GET['user'] ) ? $_GET['user'] : 'nobody';&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it would be possible to write its simplified version:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$username = $_GET['user'] ?? 'nobody';&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Spaceship operator (&amp;lt;=&amp;gt;)&lt;/h3&gt;

&lt;p&gt;Commonly used for comparison functions, this operator returns -1, 0, or 1 depending on the comparison result.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;echo 1 &amp;lt;=&amp;gt; 1; // 0
echo 1 &amp;lt;=&amp;gt; 2; // -1
echo 2 &amp;lt;=&amp;gt; 1; // 1&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;PHP 8 Compatibility and WordPress Versions&lt;/h2&gt;

&lt;p&gt;Keeping compatibility with a so wide range of versions makes things harder. Compatibility with PHP 8 (8.0, 8.1, and 8.2) is &lt;a href="https://make.wordpress.org/core/handbook/references/php-compatibility-and-wordpress-versions/" rel="noreferrer noopener"&gt;still in Beta&lt;/a&gt;. Will dropping support to PHP 5.6 give enough room to focus on PHP 8.x? Let's hope so!&lt;/p&gt;

&lt;p&gt;And you, did you already update your PHP site version?&lt;/p&gt;

</description>
      <category>gratitude</category>
    </item>
    <item>
      <title>"WordPress with capital P." Does it matter?</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Mon, 24 Oct 2022 23:51:21 +0000</pubDate>
      <link>https://dev.to/felipeelia/wordpress-with-capital-p-does-it-matter-2l5a</link>
      <guid>https://dev.to/felipeelia/wordpress-with-capital-p-does-it-matter-2l5a</guid>
      <description>&lt;p&gt;If you are looking for a job in the WordPress ecosystem or if you run a business specialized in WP, &lt;strong&gt;can a single letter make any difference? The short answer is yes&lt;/strong&gt;, that single letter can help (or not) to show knowledge and attention to detail.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Looking for a WordPress-related job?&lt;/strong&gt; Review your CV and make sure you have WordPress spelled right.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/code-is-poetry.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OoTdObr4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/code-is-poetry.jpg" alt="Cordões de crachá com o logo do WordPress, WordPress.org e a frase Code is Poetry" width="768" height="431"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Why does it make a difference?&lt;/h2&gt;

&lt;p&gt;Different communities have different degrees of concern with their characteristic. &lt;strong&gt;For the WordPress community, the importance of how its name is spelled sometimes may seem disproportionate.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Anyway, the truth is that &lt;strong&gt;&lt;em&gt;WordPress&lt;/em&gt; is the only correct way to write it&lt;/strong&gt;. All the others are wrong and, although it is ignored on most occasions, during a hiring process it can indicate a lack of knowledge or attention.&lt;/p&gt;

&lt;p&gt;How much that really makes any difference varies a lot. It can be essential, it can be a tiebreaker, or not be important at all. Nonetheless, if you know the right way to write it, it is always better to use it.&lt;/p&gt;

&lt;h3&gt;Isn't that too much?&lt;/h3&gt;

&lt;p&gt;It could be. The fact is that there is a right way and &lt;strong&gt;WordPress core even has a function just to make that change&lt;/strong&gt;:  &lt;a href="https://developer.wordpress.org/reference/functions/capital_p_dangit/" rel="noreferrer noopener"&gt;capital_p_dangit()&lt;/a&gt;. The function description can give you an idea of how important some folks consider WordPress name spell:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Forever eliminate “Wordpress” from the planet (or at least the little bit we can influence).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Quite severe, right?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/10/wordpress-capital-p-dangit.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gudXTP4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/10/wordpress-capital-p-dangit.png" alt="Captura de tela da página da documentação da função capital_P_dangit do WordPress.org" width="800" height="266"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;A specialist would &lt;em&gt;never&lt;/em&gt; write &lt;em&gt;Wordpress&lt;/em&gt; or &lt;em&gt;Word press&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;A person or a company that claims themselves as a WordPress specialist should've already stumbled upon this information.&lt;/strong&gt; In summary, here are the most important points:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing it right does not make anyone a specialist but&lt;/li&gt;



&lt;li&gt;Writing it wrong does make someone less of a specialist;&lt;/li&gt;



&lt;li&gt;There are people out there writing it wrongly who know more about WP than people writing it right;&lt;/li&gt;



&lt;li&gt;It is okay to write w&lt;em&gt;ordpress&lt;/em&gt; (all lowercase), &lt;em&gt;wp,&lt;/em&gt; or &lt;em&gt;WP&lt;/em&gt; in informal communications like slack messages. &lt;em&gt;Wordpress&lt;/em&gt; and &lt;em&gt;Word press&lt;/em&gt; are more noticeable mistakes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First impressions are important and on some occasions, we need to assure that someone knows or does not know WordPress. If writing it right can't give total certainty, writing it wrong certainly does not help.&lt;/p&gt;

&lt;p&gt;As last, imagine this convo:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;– Hey, do you like video games? Which are your favorite characters?&lt;br&gt;– I love it! I like that green dude Zelda, green Mario, and Yellow Sub-Zero!&lt;br&gt;– Oh, you mean Link, Luigi, and Scorpion, right?&lt;br&gt;– Yeah, yeah!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Does that mean the person is a bad player? Absolutely not! It does mean they do not read much about the topic, though.&lt;/p&gt;

&lt;h2&gt;My first contact with this&lt;/h2&gt;

&lt;p&gt;I want to tell you how I was first told about this difference:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;After meeting the WordPress community here in Curitiba in May 2016, &lt;a href="https://www.meetup.com/pt-BR/wpcuritiba/events/231889574/" rel="noreferrer noopener"&gt;I asked if I could give a talk the next month&lt;/a&gt;. When I sent my slide deck, &lt;a href="https://danielkossmann.com/" rel="noreferrer noopener"&gt;Daniel Kossmann&lt;/a&gt; asked for a change: WordPress has a capital P.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had been using WP for years at that point but didn't have any contact with the community. After that day, I never wrote it wrong again.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.facebook.com/ComunidadeWordPressCuritiba/photos/pb.100064348375282.-2207520000./927304387414912/?type=3" rel="noreferrer noopener"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XaIM4oL0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/10/foto-meetup-curitiba-2016-1024x682.jpg" alt="Felipe Elia palestrando sobre WordPress no meetup de Curitiba" width="800" height="533"&gt;&lt;/a&gt;A picture of that talk! :)&lt;/p&gt;

&lt;p&gt;In fact, &lt;strong&gt;for &lt;a href="https://make.wordpress.org/community/handbook/wordcamp-organizer/planning-details/speakers/speaking-at-a-wordcamp/#preparing-your-talk" rel="noreferrer noopener"&gt;any talks in WordCamps&lt;/a&gt;, WordPress docs demand the usage of a capital P all the time&lt;/strong&gt;. Obviously, that rule also applies to meetups or any official community event.&lt;/p&gt;

&lt;h2&gt;Writing Wordpress can indicate "just" lack of attention&lt;/h2&gt;

&lt;p&gt;I want to write a post about &lt;em&gt;soft skills&lt;/em&gt; and personal characteristics not necessarily related to technology but one thing is certain: no one likes people that do not pay attention.&lt;/p&gt;

&lt;p&gt;That said, always review and be careful with your resumé and official communication.&lt;/p&gt;

&lt;h2&gt;I am a client or I have a job to offer. How much does that matter?&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;As you can imagine, it depends.&lt;/strong&gt; If you had a recommendation from someone else, that should matter more than a single letter in a name. If the company or person is completely new to you, that can indicate that their knowledge of WordPress is not that good.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If that is a lead role or something critical to your company, I recommend you to give a look at some other competitors.&lt;/strong&gt; If this detail passed unnoticed, something else could too.&lt;/p&gt;

&lt;h2&gt;Okay, what is next?&lt;/h2&gt;

&lt;p&gt;Now that you know, spread the word. Do not judge those who didn't see this detail yet but explain that this can make a difference. Be nice though, no one has the obligation to know it :)&lt;/p&gt;








&lt;p&gt;The thumbnail was made using &lt;a href="https://www.thewordfinder.com/simpsons-chalkboard/" rel="noreferrer noopener nofollow"&gt;https://www.thewordfinder.com/simpsons-chalkboard/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>php</category>
      <category>wordpress</category>
      <category>jobs</category>
      <category>resume</category>
    </item>
    <item>
      <title>WordPress, Object Cache, and Redis</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Mon, 15 Aug 2022 22:03:00 +0000</pubDate>
      <link>https://dev.to/felipeelia/wordpress-object-cache-and-redis-50l1</link>
      <guid>https://dev.to/felipeelia/wordpress-object-cache-and-redis-50l1</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://felipeelia.dev/wordpress-object-cache-and-redis/"&gt;my blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Do you want to &lt;strong&gt;make your WordPress website faster while leveling up your WP programming skills&lt;/strong&gt;? Object Cache may be your answer!&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before we go into Object Cache… What is cache?&lt;/li&gt;
&lt;li&gt;WordPress Object Cache&lt;/li&gt;
&lt;li&gt;
How to “store” things in memory? Redis or Memcached

&lt;ul&gt;
&lt;li&gt;What do I need to use WordPress Object Cache with Redis?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
The Redis Object Cache WordPress plugin

&lt;ul&gt;
&lt;li&gt;Same Redis for different sites at the same server&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;How the Object Cache plugin works&lt;/li&gt;
&lt;li&gt;Let’s give a look at some code&lt;/li&gt;
&lt;li&gt;
Cache functions available in  WordPress

&lt;ul&gt;
&lt;li&gt;Key, value, group, and expiration&lt;/li&gt;
&lt;li&gt;
Expiration

&lt;ul&gt;
&lt;li&gt;Event-driven&lt;/li&gt;
&lt;li&gt;Time-driven&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Transients API and Object Cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the &lt;a href="https://felipeelia.dev/what-is-an-api/"&gt;What is an API&lt;/a&gt; post, I've briefly mentioned WordPress Object Cache and how I am using Redis here in the blog. In this post, we will give a better look into both of those things.&lt;/p&gt;

&lt;h2 id="antes-de-object-cache-o-que-e-cache"&gt;Before we go into &lt;em&gt;Object Cache&lt;/em&gt;... What is cache?&lt;/h2&gt;

&lt;p&gt;Before we start talking about Redis, we need to talk about Object Cache. And before we talk about Object Cache -- you saw it coming -- we need to talk about cache in general.&lt;/p&gt;

&lt;p&gt;Looking for definitions of what is cache on the Internet, common sense seems to be something like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cache is an &lt;strong&gt;intermediate storage with quick access&lt;/strong&gt;, placed between the consumer and the main storage, potentially saving a longer trip.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Look at the example below. In the first request, we go all the way through the origin server but the server cache saves a copy of the response. In the second request, the copy is served, &lt;strong&gt;saving time by not going to the origin server&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/08/cache-definition-lg2x.webp"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oKKAgqNr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/08/cache-definition-lg2x-1024x512.webp" alt="Two line diagram: in the first one the request goes from the client to the cache server and reaches the origin server. In the second one, the cache server answers the request." width="800" height="400"&gt;&lt;/a&gt;Image credits: &lt;a href="https://www.keycdn.com/support/cache-definition-explanation"&gt;KeyCDN blog&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With that in mind, we can start thinking about all the several trips needed to visit a website and all the intermediate steps we can insert to save time:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Browser cache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Between your browser and the site server, if there is a &lt;strong&gt;valid copy of the page on your computer&lt;/strong&gt;, we save a trip. In fact, we save the entire trip in this case.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;If you are using a CDN like Cloudflare on your website and &lt;strong&gt;if there is a valid copy of the content in the CDN&lt;/strong&gt;, there is no reason to ask for a new copy. It is enough to send just the copy and we save a trip.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;WP's cache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;In your WordPress website, if a post was already brought from the database and &lt;strong&gt;if the version of the post in memory is still valid&lt;/strong&gt;, why go to the database again?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There are lots of other intermediate places we could save a version of the information, these are just some examples.  &lt;/p&gt;

&lt;h2 id="o-object-cache-do-wordpress"&gt;WordPress Object Cache&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;WordPress Object Cache&lt;/em&gt; is simple and understand how it works can make the difference during your next job interview ;-)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I said in the &lt;a href="https://felipeelia.dev/what-is-an-api/"&gt;What is an API&lt;/a&gt; post, memory access is always faster than disk access. With that in mind, &lt;strong&gt;if we brought a post from the database and put that in memory, we do not need to go to the database to fetch it again&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/08/memory-hierarchy.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cUOnEbQC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/08/memory-hierarchy.png" alt="Extended Memory Hierarchy. From bottom to top: Off-line Storage (slower), Hard Disk, RAM, Cache, CPU Registers (faster.) The faster, the more expensive it is." width="638" height="479"&gt;&lt;/a&gt;The image quality is not very good but the image is great to understand the relationship between storage and speed.&lt;/p&gt;

&lt;p&gt;The problem is that in WordPress default implementation, &lt;strong&gt;it will be in memory only until the end of the request&lt;/strong&gt;. If the user refreshes the page, we will need to go to the database again.&lt;/p&gt;

&lt;p&gt;MySQL is smart enough to notice if a piece of information was requested recently and will make it available in a quicker way (basically storing it in its own memory part). &lt;strong&gt;Although faster, it will not be as faster as not going to MySQL at all.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;By default, this post (or any other piece of info we want) requested at the beginning of the execution is &lt;strong&gt;stored using a class called &lt;a href="https://developer.wordpress.org/reference/classes/wp_object_cache"&gt;WP_Object_Cache&lt;/a&gt;&lt;/strong&gt;. Its main goal is to save trips to the database and it works basically using key-value pairs. The problem is, like I said, all that only lasts one request. For the next one, we have to do everything again.&lt;/p&gt;

&lt;h2 id="como-gravar-coisas-na-memoria-redis-ou-memcached"&gt;How to "store" things in memory? Redis or Memcached&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Softwares like &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt; or &lt;a href="https://memcached.org/"&gt;Memcached&lt;/a&gt; are in-memory databases.&lt;/strong&gt; They can do more than that -- especially Redis -- but for our problem with WordPress, its key-pair value in-memory storage is everything we need.&lt;/p&gt;

&lt;p&gt;In this post, I will use Redis as an example but Memcached installation and usage are very similar.&lt;/p&gt;

&lt;p&gt;&amp;lt;!-- /wp:column --&amp;gt;&lt;/p&gt;

&lt;h3 id="o-que-eu-preciso-para-usar-object-cache-com-redis-no-wordpress"&gt;What do I need to use WordPress Object Cache with Redis?&lt;/h3&gt;

&lt;p&gt;The requirements to use WordPress Object Cache with Redis are quite simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A WordPress website&lt;/li&gt;
&lt;li&gt;Redis running in your infrastructure&lt;/li&gt;
&lt;li&gt;A WordPress plugin to connect WP to Redis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best way to have step #2 done is to contact your hosting provider. On Cloudways, for example, you need to &lt;a href="https://www.cloudways.com/blog/install-redis-cache-wordpress/#activating-redis-on-the-cloudways-platform"&gt;click on a button on their Dashboard to install Redis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2021/08/como-habilitar-redis-na-cloudways.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7WzkBp5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2021/08/como-habilitar-redis-na-cloudways.jpg" alt="How to install Redis on Cloudways: Server Management -&amp;gt; Settings &amp;amp; Packages -&amp;gt; Packages -&amp;gt; Redis (Install)" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="o-plugin-redis-object-cache"&gt;The &lt;em&gt;Redis Object Cache&lt;/em&gt; WordPress plugin&lt;/h2&gt;

&lt;p&gt;As I said in the other post, the plugin I use is &lt;a href="https://wordpress.org/plugins/redis-cache/"&gt;Redis Object Cache&lt;/a&gt;. Install and configure it is not hard. Out of the box, it will try to connect to a Redis instance in the same server (&lt;code&gt;127.0.0.1&lt;/code&gt;) on port &lt;code&gt;6379&lt;/code&gt; using Redis database number &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://br.wordpress.org/plugins/redis-cache/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8_rs6TAG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/redis-object-cache-plugin.png" alt='Screenshot of the "Redis Object Cache" plugin in WordPress.org Directory.' width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To have the plugin working, it will need to copy its &lt;code&gt;object-cache.php&lt;/code&gt; file from its own &lt;em&gt;includes&lt;/em&gt; folder to the &lt;em&gt;wp-content&lt;/em&gt; folder of your WordPress installation. If for whatever reason like directory permissions, it is not possible to copy the file automatically, you will need to copy it manually.&lt;/p&gt;

&lt;h3 id="mesmo-redis-com-diferentes-sites-no-mesmo-servidor"&gt;Same Redis for different sites at the same server&lt;/h3&gt;

&lt;p&gt;I have another blog running on this same server, sharing the same Redis installation. To avoid conflicts between stored information for each site, I had to define  &lt;code&gt;define( 'WP_REDIS_DATABASE', 0 );&lt;/code&gt; on one and &lt;code&gt;define( 'WP_REDIS_DATABASE', 1 );&lt;/code&gt; on the other.&lt;/p&gt;

&lt;p&gt;To adjust the configuration you will need to place some constants in your &lt;em&gt;wp-config.php&lt;/em&gt; file. The full list of settings is available on the &lt;a href="https://github.com/rhubarbgroup/redis-cache/wiki/Connection-Parameters"&gt;plugin wiki&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="como-o-plugin-de-object-cache-funciona"&gt;How the &lt;em&gt;Object Cache &lt;/em&gt;plugin works&lt;/h2&gt;

&lt;p&gt;Inside the &lt;a href="https://developer.wordpress.org/reference/functions/wp_start_object_cache/"&gt;wp_start_object_cache()&lt;/a&gt; function (see below), executed at the beginning of WordPress load flow, WP will detect if there is an &lt;code&gt;object-cache.php&lt;/code&gt; drop-in or not. If it is available, the file is loaded, otherwise, the default implementation is used. After that, the cache is initiated.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function wp_start_object_cache() {
    ...
        if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
            &lt;strong&gt;require_once WP_CONTENT_DIR . '/object-cache.php';&lt;/strong&gt;
            ...
        }
    ...
 

    &lt;strong&gt;// If there is no external cache, loads WP's.&lt;/strong&gt;
    if ( ! wp_using_ext_object_cache() ) {
        require_once ABSPATH . WPINC . '/cache.php';
    }
 
    require_once ABSPATH . WPINC . '/cache-compat.php';
 
    ...
    &lt;strong&gt;wp_cache_init();&lt;/strong&gt;
    ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Redis Object Cache&lt;/em&gt;'s &lt;code&gt;object-cache.php&lt;/code&gt; contents can be seen &lt;a href="https://plugins.trac.wordpress.org/browser/redis-cache/trunk/includes/object-cache.php"&gt;here&lt;/a&gt;. It is formed by an implementation of the &lt;code&gt;WP_Object_Cache&lt;/code&gt; class (last part of the file) and the several functions that use it like &lt;code&gt;wp_cache_add&lt;/code&gt;, &lt;code&gt;wp_cache_get&lt;/code&gt;, and  &lt;code&gt;wp_cache_delete&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/08/doc-back-to-the-future-ready.webp"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JS_-S4t2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/08/doc-back-to-the-future-ready.webp" alt='Animated GIF of Doc Brown from "Back to the Future" holding electric cables and saying "Ready!"' width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="dando-uma-olhada-em-codigo"&gt;Let's give a look at some code&lt;/h2&gt;

&lt;p&gt;If you need some code to understand things better that is okay, I am one of those too. Here is a part of the code executed when you call &lt;code&gt;get_post( 123 );&lt;/code&gt; in WordPress 6.0.1.&lt;/p&gt;

&lt;p&gt;The code starts in &lt;a href="https://github.com/WordPress/WordPress/blob/6.0.1/wp-includes/post.php#L990"&gt;wp-includes/post.php&lt;/a&gt;, where get_post calls &lt;code&gt;WP_Post::get_instance( $post )&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, in &lt;a href="https://github.com/WordPress/WordPress/blob/6.0.1/wp-includes/class-wp-post.php#L231"&gt;wp-includes/class-wp-post.php&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;final class WP_Post {
    ...
    public static function get_instance( $post_id ) {
        &lt;strong&gt;$_post = wp_cache_get( $post_id, 'posts' );&lt;/strong&gt;

        if ( ! $_post ) {
            ...
            &lt;strong&gt;wp_cache_add( $_post-&amp;gt;ID, $_post, 'posts' );&lt;/strong&gt;
        } 
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At first, it checks if the cached value exists (&lt;code&gt;wp_cache_get&lt;/code&gt;). If it exists it is used, otherwise, the post is fetched and then cached (&lt;code&gt;wp_cache_add&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;If we look at the &lt;code&gt;wp_cache_add&lt;/code&gt; function code, we can see it is nothing more than a simple wrapper for the &lt;code&gt;add&lt;/code&gt; method of the &lt;code&gt;WP_Object_Cache&lt;/code&gt; instance stored in the global variable &lt;code&gt;$wp_object_cache&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
    global $wp_object_cache;
 
    return $wp_object_cache-&amp;gt;add( $key, $data, $group, (int) $expire );
}&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="as-funcoes-de-cache-disponiveis-no-wordpress"&gt;Cache functions available in  WordPress&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://developer.wordpress.org/reference/classes/wp_object_cache/#wp_cache-functions"&gt;official documentation lists some of the most important cache functions&lt;/a&gt; and I am transcribing them here. WordPress's core itself uses them in several places but you can call them too in your theme or plugin.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wp_cache_add( $key, $data, $group = '', $expire = 0 ) // If exists, do not overwrite
wp_cache_set( $key, $data, $group = '', $expire = 0 ) // If exists, overwrite
wp_cache_replace( $key, $data, $group, $expire ) // If does not exist, do nothing
wp_cache_get( $key, $group = '', $force = false, $found = null )
wp_cache_delete( $key, $group = '' )
wp_cache_flush()&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="chave-valor-grupo-e-expiracao"&gt;Key, value, group, and expiration&lt;/h3&gt;

&lt;p&gt;Most of the &lt;code&gt;wp_cache_*&lt;/code&gt; functions use four parameters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Key:&lt;/strong&gt; the identified for the object stored in cache. The post ID, for example.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value:&lt;/strong&gt; the object stored in cache. In our example, the post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group (optional):&lt;/strong&gt; You can optionally group values. Previously, it was used simply to organize things but coming in WordPress 6.1, there will be a &lt;a href="https://core.trac.wordpress.org/ticket/4476"&gt;new &lt;code&gt;wp_cache_flush_group&lt;/code&gt; function&lt;/a&gt; to flush all objects of a certain group. You will be able, for example, to delete just keys of a certain plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiration (optional):&lt;/strong&gt; for how long a cached value should be considered valid. Let's give it a closer look now.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="expiracao"&gt;Expiration&lt;/h3&gt;

&lt;p&gt;When we talk about cache, one of the most important concepts is expiration. &lt;strong&gt;Is the information we have still valid?&lt;/strong&gt; This is a key part of any cache implementation, including WordPress Object Cache.&lt;/p&gt;

&lt;p&gt;So, how do we decide for how long a cached object should be considered valid?&lt;/p&gt;

&lt;h4 id="baseado-em-um-evento"&gt;Event-driven&lt;/h4&gt;

&lt;p&gt;Let's say you are caching the list of posts of the biggest content. You get all the posts, apply the &lt;code&gt;the_content&lt;/code&gt; filter in all of them, and check how many characters they have. Pretty intensive, right? This deserves to be cached.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What can change the result of this process? Only if a post is created, deleted, or edited, right?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this case, our cache does not need to expire. &lt;strong&gt;It is enough to invalidate the result we have using a related &lt;a href="https://felipeelia.com.br/o-que-sao-hooks/"&gt;hook&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h4 id="baseado-em-tempo"&gt;Time-driven&lt;/h4&gt;

&lt;p&gt;If what you are caching comes, for example, from something external like an API, &lt;strong&gt;the event that invalidates the cache is not under our control&lt;/strong&gt;. In this case, we need to &lt;strong&gt;check the results from time to time&lt;/strong&gt; in the external API and update the value we have stored.&lt;/p&gt;

&lt;h2 id="transients-api-e-object-cache"&gt;Transients API and Object Cache&lt;/h2&gt;

&lt;p&gt;If you read the post or watched the YouTube video about the &lt;a href="https://felipeelia.com.br/cache-facil-no-wordpress-transients-api/"&gt;WordPress Transients API&lt;/a&gt;, the central idea here is not new: &lt;strong&gt;a key-value pair that avoids a long process is the essential idea behind both things&lt;/strong&gt;. In fact, in a certain aspect, it is indeed the same thing. Look at the implementation of the &lt;code&gt;get_transient&lt;/code&gt; function:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function get_transient( $transient ) {
    if ( wp_using_ext_object_cache() || wp_installing() ) {
        $value = &lt;strong&gt;wp_cache_get( $transient, 'transient' )&lt;/strong&gt;;
    } else {
        ...
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Basically, if you are using an external mechanism for Object Caching, the transient will be stored there. Otherwise, the regular database will be used. Interesting, huh? Make sure to check that content too!&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>redis</category>
      <category>php</category>
      <category>performance</category>
    </item>
    <item>
      <title>WordPress, Object Cache e Redis</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Mon, 15 Aug 2022 21:55:04 +0000</pubDate>
      <link>https://dev.to/felipeelia/wordpress-object-cache-e-redis-2chc</link>
      <guid>https://dev.to/felipeelia/wordpress-object-cache-e-redis-2chc</guid>
      <description>&lt;p&gt;&lt;em&gt;Originalmente publicado no &lt;a href="https://felipeelia.com.br/wordpress-object-cache-e-redis/"&gt;meu blog&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Quer um jeito fácil de deixar o seu &lt;strong&gt;site WordPress mais rápido&lt;/strong&gt; e ainda por cima dar um &lt;strong&gt;&lt;em&gt;up &lt;/em&gt;no seu nível de programação com WP&lt;/strong&gt;? O Object Cache pode ser a resposta para as duas coisas!&lt;/p&gt;

&lt;h2&gt;
  
  
  Índice
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Antes de Object Cache… O que é cache?&lt;/li&gt;
&lt;li&gt;O Object Cache do WordPress&lt;/li&gt;
&lt;li&gt;
Como “gravar” coisas na memória? Redis ou Memcached

&lt;ul&gt;
&lt;li&gt;O que eu preciso para usar Object Cache com Redis no WordPress?&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
O plugin Redis Object Cache

&lt;ul&gt;
&lt;li&gt;Mesmo Redis com diferentes sites no mesmo servidor&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Como o plugin de Object Cache funciona&lt;/li&gt;
&lt;li&gt;Dando uma olhada em código&lt;/li&gt;
&lt;li&gt;
As funções de cache disponíveis no WordPress

&lt;ul&gt;
&lt;li&gt;Chave, valor, grupo e expiração&lt;/li&gt;
&lt;li&gt;
Expiração

&lt;ul&gt;
&lt;li&gt;Baseado em um evento&lt;/li&gt;
&lt;li&gt;Baseado em tempo&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Transients API e Object Cache&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No post sobre &lt;a href="https://felipeelia.com.br/o-que-e-uma-api/"&gt;o que é uma API&lt;/a&gt;, comentei brevemente sobre o cache de objetos do WordPress e como eu uso o Redis aqui no blog.  Nesse post vamos dar uma olhada melhor nessas duas coisas.&lt;/p&gt;

&lt;h2 id="antes-de-object-cache-o-que-e-cache"&gt;Antes de &lt;em&gt;Object Cache&lt;/em&gt;... O que é cache?&lt;/h2&gt;

&lt;p&gt;Antes de falarmos sobre Redis, precisamos falar sobre Object Cache. E antes de falarmos sobre Object Cache, você adivinhou, vamos falar rapidamente sobre cache em geral.&lt;/p&gt;

&lt;p&gt;Procurando por definições sobre o que é cache na internet, o senso comum parece ser algo como o seguinte:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cache é um lugar de &lt;strong&gt;armazenamento intermediário e acesso rápido&lt;/strong&gt;, localizado entre o consumidor e o armazenamento principal, potencialmente economizando uma viagem mais demorada.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Veja o exemplo abaixo. Na primeira vez a requisição vai até o servidor final, mas o servidor de cache guarda uma cópia. &lt;strong&gt;Na segunda vez é servida a cópia, economizando a viagem até o servidor.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/08/cache-definition-lg2x.webp"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oKKAgqNr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/08/cache-definition-lg2x-1024x512.webp" alt="Diagrama com duas linhas: na primeira a requisição sai do client, passa pelo servidor de cache e chega até o servidor de origem. Na segunda, o servidor de cache já responde a requisição." width="800" height="400"&gt;&lt;/a&gt;Peguei a imagem lá no &lt;a href="https://www.keycdn.com/support/cache-definition-explanation"&gt;blog do KeyCDN&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Com isso em mente, podemos pensar nas várias viagens necessárias para abrir um site e nos vários intermediários que podemos inserir para economizar viagens:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Browser cache&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Entre o seu navegador e o servidor do site, se houver uma &lt;strong&gt;cópia válida do site no seu computador&lt;/strong&gt;, economizamos uma viagem. Na verdade, a viagem inteira nesse caso.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CDN&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Se seu site passar por um CDN como Cloudflare e &lt;strong&gt;se o conteúdo gravado no CDN ainda for válido&lt;/strong&gt;, não há porque solicitar uma nova cópia, basta enviar a antiga e economizamos uma viagem.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cache do WP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No seu site WordPress, se um post já foi trazido do banco de dados uma vez, se a &lt;strong&gt;informação que temos na memória ainda é valida&lt;/strong&gt;, por que ir até o banco de dados novamente?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Existem muitas outras viagens em que podemos adicionar um lugar intermediário para salvar uma versão da informação esses são só alguns exemplos. Ah, e &lt;strong&gt;a pronúncia é a mesma que CASH (dinheiro)&lt;/strong&gt;, não cachê ou qualquer outra coisa.&lt;/p&gt;

&lt;h2 id="o-object-cache-do-wordpress"&gt;O &lt;em&gt;Object Cache&lt;/em&gt; do WordPress&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;O &lt;em&gt;Object Cache&lt;/em&gt; do WordPress é simples e entender como ele funciona pode ser um diferencial na sua próxima entrevista de emprego ;-)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Como falei no post sobre &lt;a href="https://felipeelia.com.br/o-que-e-uma-api/"&gt;o que é uma API&lt;/a&gt;, acesso a memória é sempre mais rápido que acesso a disco. Com isso em mente, se no início do processamento de uma página &lt;strong&gt;já trouxemos um post para memória, não há necessidade de irmos no banco novamente para buscá-lo&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/08/memory-hierarchy.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cUOnEbQC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/08/memory-hierarchy.png" alt="Hierarquia de memória estendida. Da base para o topo: armazenamento offline (mais lento), disco rígido, memória RAM, cache do processador e CPU (mais rápido). Quando mais rápido, mais caro." width="638" height="479"&gt;&lt;/a&gt;A qualidade não é das melhores, mas a imagem é ótima para entender a relação entre armazenamento e velocidade.&lt;/p&gt;

&lt;p&gt;O problema é que, na implementação padrão do WordPress, &lt;strong&gt;ele só ficará na memória até o fim do processamento daquela página&lt;/strong&gt;. Precisa dele novamente se o usuário recarregar a página? Vamos ter que ir no banco de dados novamente.&lt;/p&gt;

&lt;p&gt;O MySQL é inteligente o suficiente para notar se uma informação já foi solicitada recentemente e deixá-la disponível mais rapidamente, mas mesmo assim não é tão rápido. &lt;strong&gt;E, no fim das contas, se estamos indo até o MySQL, estamos fazendo uma viagem maior de qualquer forma.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Por padrão, esse post solicitado no começo do processo (ou qualquer outra informação que quisermos) é &lt;strong&gt;gravado usando uma classe chamada &lt;a href="https://developer.wordpress.org/reference/classes/wp_object_cache"&gt;WP_Object_Cache&lt;/a&gt;&lt;/strong&gt;. Seu objetivo principal é economizar viagens ao banco de dados e ela funciona basicamente como um par chave-valor. O problema, como eu disse, é que isso tudo só dura uma requisição. Para a próxima, fazemos tudo de novo.&lt;/p&gt;

&lt;h2 id="como-gravar-coisas-na-memoria-redis-ou-memcached"&gt;Como "gravar" coisas na memória? Redis ou Memcached&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Programas como &lt;a href="https://redis.io/"&gt;Redis&lt;/a&gt; ou &lt;a href="https://memcached.org/"&gt;Memcached&lt;/a&gt; são bancos de dados que armazenam informações em memória.&lt;/strong&gt; Eles podem fazer mais do que isso, principalmente o Redis, mas para o nosso problema com o WordPress, o armazenamento em memória de pares chave-valor do Redis é tudo o que realmente precisamos.&lt;/p&gt;

&lt;p&gt;Ao longo do post vou usar o Redis como exemplo, mas a instalação e utilização com memcached é bem parecida.&lt;/p&gt;

&lt;h3 id="o-que-eu-preciso-para-usar-object-cache-com-redis-no-wordpress"&gt;O que eu preciso para usar Object Cache com Redis no WordPress?&lt;/h3&gt;

&lt;p&gt;A lista de pré-requisitos para usar o Object Cache do WordPress com Redis é bem simples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Um site WordPress&lt;/li&gt;
&lt;li&gt;Redis funcionando na sua infraestrutura&lt;/li&gt;
&lt;li&gt;Um plugin WordPress para conectar o WP ao Redis&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para o segundo item, o mais rápido é entrar em contato com sua empresa de hospedagem. Na Cloudways, por exemplo, você precisa &lt;a href="https://www.cloudways.com/blog/install-redis-cache-wordpress/#activating-redis-on-the-cloudways-platform"&gt;apertar um botão no Painel para instalar o Redis&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2021/08/como-habilitar-redis-na-cloudways.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7WzkBp5x--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2021/08/como-habilitar-redis-na-cloudways.jpg" alt="Como habilitar o Redis na Cloudways: Server Management -&amp;gt; Settings &amp;amp; Packages -&amp;gt; Packages -&amp;gt; Redis (Install)" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="o-plugin-redis-object-cache"&gt;O plugin &lt;em&gt;Redis Object Cache&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Como eu disse no outro post, o plugin que eu uso é o &lt;a href="https://br.wordpress.org/plugins/redis-cache/"&gt;Redis Object Cache&lt;/a&gt;. Instalá-lo e configurá-lo é relativamente simples. Por padrão, ele tentará se conectar a uma instância do Redis localizada no próprio servidor (&lt;code&gt;127.0.0.1&lt;/code&gt;) na porta &lt;code&gt;6379&lt;/code&gt; usando o banco de dados Redis de número &lt;code&gt;0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://br.wordpress.org/plugins/redis-cache/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8_rs6TAG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/redis-object-cache-plugin.png" alt='Captura de tela do cabeçalho do plugin WordPress "Redis Object Cache" no repositório de plugins.' width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para que o plugin funcione, ele precisa copiar o arquivo &lt;code&gt;object-cache.php&lt;/code&gt; de dentro de sua própria pasta &lt;em&gt;includes&lt;/em&gt; para a pasta &lt;em&gt;wp-content&lt;/em&gt; da sua instalação WordPress. Se por qualquer motivo, como permissão de diretórios, não for possível copiar o arquivo automaticamente, será necessário copiá-lo manualmente.&lt;/p&gt;

&lt;h3 id="mesmo-redis-com-diferentes-sites-no-mesmo-servidor"&gt;Mesmo Redis com diferentes sites no mesmo servidor&lt;/h3&gt;

&lt;p&gt;O meu outro blog, o &lt;a href="https://melancianacabeca.com.br/"&gt;Melancia na Cabeça&lt;/a&gt;, também é armazenado neste servidor e compartilha a mesma instalação do Redis. Para evitar que os valores armazenados pelos dois sites entrem em conflito, eu precisei definir &lt;code&gt;define( 'WP_REDIS_DATABASE', 0 );&lt;/code&gt; em um e &lt;code&gt;define( 'WP_REDIS_DATABASE', 1 );&lt;/code&gt; no outro.&lt;/p&gt;

&lt;p&gt;Os parâmetros de configuração diferentes do padrão precisam ser adicionados no arquivo &lt;em&gt;wp-config.php&lt;/em&gt; do seu site. A lista completa de parâmetros está na &lt;a href="https://github.com/rhubarbgroup/redis-cache/wiki/Connection-Parameters"&gt;wiki do plugin&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="como-o-plugin-de-object-cache-funciona"&gt;Como o plugin de &lt;em&gt;Object Cache &lt;/em&gt;funciona&lt;/h2&gt;

&lt;p&gt;Na função &lt;a href="https://developer.wordpress.org/reference/functions/wp_start_object_cache/"&gt;wp_start_object_cache()&lt;/a&gt; (trechos abaixo), executada no início do fluxo de carregamento do WordPress, ele detecta a existência ou não do drop-in &lt;code&gt;object-cache.php&lt;/code&gt;. Se disponível, o arquivo é carregado, caso contrário a implementação padrão entra em ação. Então, o cache é instanciado.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function wp_start_object_cache() {
    ...
        if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
            &lt;strong&gt;require_once WP_CONTENT_DIR . '/object-cache.php';&lt;/strong&gt;
            ...
        }
    ...
 

    // Se não houver object cache externo, usa o padrão do WP.
    if ( ! wp_using_ext_object_cache() ) {
        require_once ABSPATH . WPINC . '/cache.php';
    }
 
    require_once ABSPATH . WPINC . '/cache-compat.php';
 
    ...
    wp_cache_init();
    ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;O conteúdo do drop-in &lt;code&gt;object-cache.php&lt;/code&gt; do &lt;em&gt;Redis Object Cache&lt;/em&gt; pode ser visto &lt;a href="https://plugins.trac.wordpress.org/browser/redis-cache/trunk/includes/object-cache.php"&gt;aqui&lt;/a&gt;. Ele é formado por uma implementação da classe &lt;code&gt;WP_Object_Cache&lt;/code&gt; (mais pro final do arquivo) e das várias funções que a utilizam como &lt;code&gt;wp_cache_add&lt;/code&gt;, &lt;code&gt;wp_cache_get&lt;/code&gt; e &lt;code&gt;wp_cache_delete&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/08/doc-back-to-the-future-ready.webp"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JS_-S4t2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/08/doc-back-to-the-future-ready.webp" alt='Doutor Brown do filme "De volta para o futuro" segurando cabos elétricos e falando "Ready!"' width="480" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="dando-uma-olhada-em-codigo"&gt;Dando uma olhada em código&lt;/h2&gt;

&lt;p&gt;Se você precisa de código para entender as coisas melhor, eu entendo. Também sou assim. Aqui está uma parte do caminho executado quando você chama &lt;code&gt;get_post( 123 );&lt;/code&gt; no WordPress 6.0.1.&lt;/p&gt;

&lt;p&gt;O código começa em &lt;a href="https://github.com/WordPress/WordPress/blob/6.0.1/wp-includes/post.php#L990"&gt;wp-includes/post.php&lt;/a&gt;, onde get_post chama &lt;code&gt;WP_Post::get_instance( $post )&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;E então em &lt;a href="https://github.com/WordPress/WordPress/blob/6.0.1/wp-includes/class-wp-post.php#L231"&gt;wp-includes/class-wp-post.php&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;final class WP_Post {
    ...
    public static function get_instance( $post_id ) {
        &lt;strong&gt;$_post = wp_cache_get( $post_id, 'posts' );&lt;/strong&gt;

        if ( ! $_post ) {
            ...
            &lt;strong&gt;wp_cache_add( $_post-&amp;gt;ID, $_post, 'posts' );&lt;/strong&gt;
        } 
        ...
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Primeiro se verifica se o cache existe (&lt;code&gt;wp_cache_get&lt;/code&gt;). Se existir é usado, senão o post é buscado e salvo no cache (&lt;code&gt;wp_cache_add&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;E só para dar uma olhada no conteúdo da função &lt;code&gt;wp_cache_add&lt;/code&gt;, veja como ela nada mais é que um envelope para o método &lt;code&gt;add&lt;/code&gt; da instância da classe &lt;code&gt;WP_Object_Cache&lt;/code&gt; armazenada na variável global &lt;code&gt;$wp_object_cache&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
    global $wp_object_cache;
 
    return $wp_object_cache-&amp;gt;add( $key, $data, $group, (int) $expire );
}&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="as-funcoes-de-cache-disponiveis-no-wordpress"&gt;As funções de cache disponíveis no WordPress&lt;/h2&gt;

&lt;p&gt;A &lt;a href="https://developer.wordpress.org/reference/classes/wp_object_cache/#wp_cache-functions"&gt;documentação oficial lista algumas das funções de cache mais importantes&lt;/a&gt; e estou transcrevendo-as aqui. O próprio core faz uso delas em vários lugares, mas você também pode chamá-las em seu tema ou plugin.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wp_cache_add( $key, $data, $group = '', $expire = 0 ) // Se existe, não sobrescreve
wp_cache_set( $key, $data, $group = '', $expire = 0 ) // Se existe, sobrescreve
wp_cache_replace( $key, $data, $group, $expire ) // Se não existe, não faz nada
wp_cache_get( $key, $group = '', $force = false, $found = null )
wp_cache_delete( $key, $group = '' )
wp_cache_flush()&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="chave-valor-grupo-e-expiracao"&gt;Chave, valor, grupo e expiração&lt;/h3&gt;

&lt;p&gt;A maioria das funções &lt;code&gt;wp_cache_*&lt;/code&gt; usam quatro parâmetros:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Chave:&lt;/strong&gt; o identificador do objeto armazenado em cache. O ID do post, por exemplo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valor:&lt;/strong&gt; o objeto armazenado propriamente dito. O próprio post.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grupo (opcional):&lt;/strong&gt; o grupo serve para -- você adivinhou -- agrupar diferentes chaves. Antes servia mais para organização, mas no WordPress 6.1, será possível chamar &lt;a href="https://core.trac.wordpress.org/ticket/4476"&gt;a nova função &lt;code&gt;wp_cache_flush_group&lt;/code&gt;&lt;/a&gt; para apagar todos os objetos de um determinado grupo, como por exemplo, tudo armazenado em cache de um determinado plugin.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expiração (opcional):&lt;/strong&gt; por quanto tempo o cache é considerado válido. Vamos dar uma olhada mais a fundo nisso.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="expiracao"&gt;Expiração&lt;/h3&gt;

&lt;p&gt;Quando falamos de cache, um conceito importantíssimo é tempo de expiração. &lt;strong&gt;A informação que temos ainda é válida?&lt;/strong&gt; Essa é uma parte chave de qualquer implementação de cache, incluindo o Object Cache do WordPress.&lt;/p&gt;

&lt;p&gt;Então, como decidimos por quanto tempo um objeto em cache deve ser considerado válido?&lt;/p&gt;

&lt;h4 id="baseado-em-um-evento"&gt;Baseado em um evento&lt;/h4&gt;

&lt;p&gt;Vamos supor que você está armazenado em cache a lista de posts com maior conteúdo. Você pega todos os posts, passa o filtro &lt;code&gt;the_content&lt;/code&gt; em todos eles e mede quantas letras cada um tem. Bem intenso, certo? Isso merece ser armazenado em cache.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O que pode fazer o resultado deste processo mudar?&lt;/strong&gt; Só um post novo ser criado ou algum existente ser editado, certo?&lt;/p&gt;

&lt;p&gt;Neste caso, nosso cache não precisa expirar. &lt;strong&gt;Basta invalidar o resultado que temos usando um &lt;a href="https://felipeelia.com.br/o-que-sao-hooks/"&gt;hook&lt;/a&gt; relacionado&lt;/strong&gt;, nesse caso, a criação de um novo post ou edição de um post que já existe.&lt;/p&gt;

&lt;h4 id="baseado-em-tempo"&gt;Baseado em tempo&lt;/h4&gt;

&lt;p&gt;Se o que você está armazenando vem, por exemplo, de um ambiente externo como uma API, o evento que invalida o cache não está sob nosso controle. Neste caso, precisamos &lt;strong&gt;verificar o resultado de tempos em tempos&lt;/strong&gt; na API externa e atualizar o valor que temos armazenado.&lt;/p&gt;

&lt;h2 id="transients-api-e-object-cache"&gt;Transients API e Object Cache&lt;/h2&gt;

&lt;p&gt;Se você leu o post ou assistiu ao vídeo sobre a &lt;a href="https://felipeelia.com.br/cache-facil-no-wordpress-transients-api/"&gt;Transients API do WordPress&lt;/a&gt;, a ideia principal aqui não é novidade: &lt;strong&gt;um par de chave-valor que evita um processo demorado é exatamente a ideia por trás das duas coisas&lt;/strong&gt;. De fato, em um certo aspecto elas são a mesma coisa. Veja a implementação da função &lt;code&gt;get_transient&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function get_transient( $transient ) {
    if ( wp_using_ext_object_cache() || wp_installing() ) {
        $value = &lt;strong&gt;wp_cache_get( $transient, 'transient' )&lt;/strong&gt;;
    } else {
        ...
    }
    ...
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Basicamente, se você está usando um mecanismo externo para Object Cache, o transiente será gravado lá. Caso contrário, o banco de dados normal será usado. Interessante, não é? Dá uma olhada lá!&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>redis</category>
      <category>performance</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>What is an API?</title>
      <dc:creator>Felipe Elia</dc:creator>
      <pubDate>Thu, 30 Jun 2022 00:11:49 +0000</pubDate>
      <link>https://dev.to/felipeelia/what-is-an-api-2463</link>
      <guid>https://dev.to/felipeelia/what-is-an-api-2463</guid>
      <description>&lt;p&gt;Do you know what is an API? Why is it important to use your favorite framework's APIs? Have you already heard about interfaces and black boxes? In this post, we will talk about all these topics with examples.&lt;/p&gt;

&lt;p&gt;I was going to write about the reasons why you should use WordPress's APIs but I had to go back to so many concepts that we have to start talking about what is an API. &lt;strong&gt;This post is for both junior and senior developers.&lt;/strong&gt; And yes, we are going to talk about &lt;em&gt;concepts&lt;/em&gt; but stay there, these are some important ones.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;API is the acronym for &lt;strong&gt;Application Programming Interface&lt;/strong&gt;. But what does that exactly mean?!&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/confused-macgyver.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8JQLbmSx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/confused-macgyver-300x225.png" alt="MacGyver confuso com a frase &amp;quot;I don't understand&amp;quot; escrita" width="300" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Application" and "programming" are the easy parts. It is the "Interface" that we need to understand better.&lt;/p&gt;

&lt;h2&gt;What is an &lt;em&gt;Interface&lt;/em&gt;?&lt;/h2&gt;

&lt;p&gt;An Interface is nothing more than the outside layer, &lt;strong&gt;the part that connects with the exterior&lt;/strong&gt;, keeping the interior safe.&lt;/p&gt;

&lt;p&gt;We deal with this concept every day and if that wasn't possible we would freak out. Imagine if you had to know all the ins and outs of everything surrounding you! Some interface examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Graphical Interface:&lt;/strong&gt; You click, the program executes. You don't need to know how it does, if you click and it does what you want that is all that matters.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ordering a meal in a restaurant:&lt;/strong&gt; You place the order and receive the food. It doesn't matter how many cooks they have, the pan color, or the stove brand.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sensory System:&lt;/strong&gt; You don't need to know how your body &lt;em&gt;smells&lt;/em&gt; something, it simply does that for you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/caixa-eletronico.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RjxsK9_M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/caixa-eletronico.gif" alt="Mulher chegando a um caixa eletrônico aberto, com um homem sentado dentro fazendo contas para dar o dinheiro." width="640" height="482"&gt;&lt;/a&gt;Insert a card and a password, and receive the money. That is all that needs to happen. It doesn't matter if it is a machine or a guy with a calculator.&lt;/p&gt;

&lt;p&gt;The whole idea is based on the concept of &lt;em&gt;inputs&lt;/em&gt; and &lt;em&gt;outputs&lt;/em&gt;. Given an input, an output is expected, disregard the implementation:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Input&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Graphical Interface&lt;/td&gt;
&lt;td&gt;Button click&lt;/td&gt;
&lt;td&gt;Desired action&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Restaurant order&lt;/td&gt;
&lt;td&gt;Place the order&lt;/td&gt;
&lt;td&gt;Receive the food&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sensory System&lt;/td&gt;
&lt;td&gt;Touch on skin&lt;/td&gt;
&lt;td&gt;Related sensation (cold, heat, etc.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ATM&lt;/td&gt;
&lt;td&gt;Insert a card and password&lt;/td&gt;
&lt;td&gt;Receive money&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This concept of input-output-no-matter-the-inside we call &lt;strong&gt;black box&lt;/strong&gt;. There is an important difference here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;A black box is what we call something that accepts an input and returns an output&lt;/strong&gt;, without necessarily revealing how it created the output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;An Interface is how you connect with the system&lt;/strong&gt;, what is exactly the expected input (a number, two numbers, a string) and how the output will look like (another number, another string). &lt;em&gt;It is like a contract.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/black-box-and-interface.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zEwbcUgi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/black-box-and-interface.jpg" alt="" width="595" height="115"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Interfaces in OOP&lt;/h3&gt;

&lt;p&gt;Here I have to open a quick parenthesis. Interfaces are also something very important in Object-Oriented Programming. The idea is exactly the same: if a class declares it implements a certain interface, it is required to implement all the interface's methods. I'll leave here the &lt;a href="https://www.php.net/manual/en/language.oop5.interfaces.php" rel="noreferrer noopener"&gt;official PHP documentation about interfaces&lt;/a&gt; but leave a comment if this is a topic you would like to see in another post.&lt;/p&gt;

&lt;h2&gt;Okay... Can we get back to APIs now?&lt;/h2&gt;

&lt;p&gt;And here is where the real post begins! Let's get back to the acronym:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Application&lt;/strong&gt; &lt;strong&gt;Programming&lt;/strong&gt; &lt;strong&gt;Interface&lt;/strong&gt; is a &lt;em&gt;part of the application only accessible via code made by a group of methods with inputs and outputs, doesn't matter their implementation&lt;/em&gt;.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Does it make more sense now?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/now-i-see-now-i-get-it.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GcrXP9iy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/now-i-see-now-i-get-it-300x167.jpg" alt="" width="300" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(For the complainers, yeah, I know you can access a REST API with your browser but that is not the intended use of it.)&lt;/p&gt;

&lt;h2&gt;WordPress's APIs&lt;/h2&gt;

&lt;p&gt;When I had the idea to write this post, I was going to talk about how important it is to use WordPress's internal APIs. WP has lots of these APIs, we've already talked about some of them here (in Portuguese):  &lt;a href="https://felipeelia.com.br/cache-facil-no-wordpress-transients-api/"&gt;Transients API&lt;/a&gt; and &lt;a href="https://felipeelia.com.br/como-criar-uma-tela-de-configuracao-para-o-seu-plugin-wordpress-com-a-settings-api-parte-1/"&gt;Settings API&lt;/a&gt; are some examples. The full list of WordPress's APIs is available at &lt;a href="https://developer.wordpress.org/apis/"&gt;https://developer.wordpress.org/apis/&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;But why should we use these APIs instead of simply writing something in the database directly or saving a file in the server?&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;There are many reasons, let's check some of them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; these concepts are not isolated but rather complementary. Also, I did not try to cover all the possible aspects, so feel free to explore any other aspect in the comments section.&lt;/p&gt;

&lt;h2&gt;Separation of concerns&lt;/h2&gt;

&lt;p&gt;This is a principle that aims to split the application into modules, each one responsible for just one thing. These modules communicate with each other using — you guessed it — interfaces. This way, &lt;strong&gt;a code that creates a product is apart from the code that deals with orders&lt;/strong&gt;, and that only &lt;em&gt;calls&lt;/em&gt; the module responsible for storing data somewhere.&lt;/p&gt;

&lt;p&gt;Many years ago, unfortunately, it was common to see PHP applications with several calls to &lt;code&gt;mysqli_real_connect&lt;/code&gt; and similars. Today that is not the reality anymore. In WordPress, for example, we have the &lt;code&gt;wpdb&lt;/code&gt; class, other frameworks use ORM but every time it is necessary to store/save some data there is an abstraction layer we can count with.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/ruptura.gif"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0DpzaIUA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/ruptura.gif" alt="" width="640" height="267"&gt;&lt;/a&gt;The &lt;em&gt;Severance&lt;/em&gt; TV Series takes separation of concerns to a WHOLE DIFFERENT level.&lt;/p&gt;

&lt;h2&gt;Readability&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;We do not write code for machines but for other human beings&lt;/strong&gt;, after all, we say "Code is poetry" for a reason. That said, it is important to look at a code for the first time and understand what it does.&lt;/p&gt;

&lt;p&gt;What is easier to understand? This&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?php
global $wpdb;
$wpdb-&amp;gt;query(
    $wpdb-&amp;gt;prepare(
        "INSERT INTO `$wpdb-&amp;gt;options` (`option_name`, `option_value`, `autoload`)
            VALUES (%s, %s, %s)
            ON DUPLICATE KEY
            UPDATE
                `option_name` = VALUES(`option_name`),
                `option_value` = VALUES(`option_value`),
                `autoload` = VALUES(`autoload`)", 
        $option,
        $serialized_value,
        $autoload
    )
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or this?&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;?php
update_option( 'my_option', 'value' );&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The second option, right? It is easy to understand we are saving an option and if we want to use any other storage mechanism like Redis or Memcached (more about this below), the part of the software calling the &lt;code&gt;update_option()&lt;/code&gt; function does not need to be changed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/code-is-poetry.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OoTdObr4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/code-is-poetry.jpg" alt="" width="768" height="431"&gt;&lt;/a&gt;Code is Poetry!&lt;/p&gt;

&lt;h2&gt;Practical Examples&lt;/h2&gt;

&lt;blockquote&gt;&lt;p&gt;Using WordPress APIs makes life easier. Sometimes, not using them make the project unfeasible.&lt;/p&gt;&lt;/blockquote&gt;

&lt;h2&gt;Files API&lt;/h2&gt;

&lt;p&gt;This is a classic case. The programmer saves the file using functions like &lt;code&gt;fopen&lt;/code&gt;, &lt;code&gt;fclose&lt;/code&gt;, etc. and everything works fine. The project grows a bit, &lt;strong&gt;infrastructure needs to scale and files start to disappear&lt;/strong&gt;. Let's give a look at some diagrams to understand it better.&lt;/p&gt;

&lt;h3&gt;Saving directly into the server (with only one web server)&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/wp-files-api-part-1-saving-directly-into-the-server.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8Zuf9X3r--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/wp-files-api-part-1-saving-directly-into-the-server.jpg" alt="" width="742" height="131"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So far, so good. The admin user sent the file to the single server and, when the user visits the site, the file will be there.&lt;/p&gt;

&lt;h3&gt;Saving directly into the server (with more than one web server)&lt;/h3&gt;

&lt;p&gt;Now let's suppose we need another server. In front of the two web servers, we place a &lt;em&gt;load balancer&lt;/em&gt;, to split traffic between them.&lt;/p&gt;

&lt;p&gt;If we save the file directly into the server, it will be stored only in the server where the admin user uploaded the file, not being found every time the requests are sent to the other web server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/wp-files-api-part-2-saving-directly-into-the-server.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lV8mQWZw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/wp-files-api-part-2-saving-directly-into-the-server.jpg" alt="" width="793" height="523"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Saving it somewhere else&lt;/h3&gt;

&lt;p&gt;Usually, the solution relies on saving the files somewhere else, like an &lt;a href="https://aws.amazon.com/s3/" rel="noreferrer noopener"&gt;Amazon S3 Bucket&lt;/a&gt;, for example. It could be anywhere, the important here is to be a place accessible to all the servers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/wp-files-api-part-3-saving-into-amazon-s3.jpg"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qBwTF9ZN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/wp-files-api-part-3-saving-into-amazon-s3.jpg" alt="" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;How do we fix this?&lt;/h3&gt;

&lt;p&gt;The solution to this example is simple and makes usage of a &lt;a href="https://github.com/humanmade/S3-Uploads"&gt;plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The most important for us here is that &lt;strong&gt;the plugin will only work for the code using WordPress's Files API&lt;/strong&gt;. It will not be able to change direct calls to &lt;code&gt;fopen&lt;/code&gt; but only calls to &lt;code&gt;$wp_filesystem-&amp;gt;put_contents()&lt;/code&gt; or functions that pass through the Files API.&lt;/p&gt;

&lt;h2&gt;Transients API&lt;/h2&gt;

&lt;p&gt;If you read the &lt;a href="https://felipeelia.com.br/cache-facil-no-wordpress-transients-api/"&gt;post about the Transients API&lt;/a&gt; and the &lt;a href="https://developer.wordpress.org/apis/handbook/transients/#function-reference"&gt;official documentation&lt;/a&gt; you'll see that it consists of basically three functions: &lt;code&gt;set_transient()&lt;/code&gt;, &lt;code&gt;get_transient()&lt;/code&gt;, and &lt;code&gt;delete_transient()&lt;/code&gt;. You could quickly implement three functions to store, get, and delete values from the database but you would be losing one of the most used pieces of infrastructure to improve performance: &lt;strong&gt;in-memory storage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Relax, it is not a big deal. When I talked about &lt;a href="https://felipeelia.com.br/tipos-de-plugin-do-wordpress/"&gt;plugin types&lt;/a&gt;, I've talked about &lt;em&gt;drop-ins&lt;/em&gt;, one of them being &lt;code&gt;object-cache.php&lt;/code&gt;. With it, it is possible to use software like Redis or Memcached to store things in memory, instead of going to the disk every time. &lt;strong&gt;Memory access is faster than disk access&lt;/strong&gt; and, because of that, these programs return things faster than the database.&lt;/p&gt;

&lt;p&gt;If you are storing things in your database directly, adding something like these programs to your infrastructure will make no difference. On the other hand, &lt;strong&gt;if you are using WordPress's API, a plugin will be enough&lt;/strong&gt;, it is just a matter of configuring and placing its &lt;em&gt;drop-in&lt;/em&gt; and things will automatically work. If you want to change between Redis and Memcached you won't need to worry too, as the implementation will change but &lt;em&gt;the interface you are using remains the same&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://felipeelia.com.br/wp-content/uploads/2022/06/redis-object-cache-plugin.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8_rs6TAG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://felipeelia.com.br/wp-content/uploads/2022/06/redis-object-cache-plugin.png" alt="" width="800" height="360"&gt;&lt;/a&gt;Here in the blog, I use the &lt;a href="https://br.wordpress.org/plugins/redis-cache/" rel="noreferrer noopener"&gt;Redis Object Cache&lt;/a&gt; plugin&lt;/p&gt;

&lt;h2&gt;WordPress REST API&lt;/h2&gt;

&lt;p&gt;I've already talked about this topic years ago but it is still useful. If you got here wanting to learn more about &lt;a href="https://felipeelia.com.br/a-api-rest-do-wordpress/"&gt;WordPress REST API&lt;/a&gt; you can check this other post. I'm pretty sure you will like it!&lt;/p&gt;








&lt;p&gt;This is a giant post, I know. If you can share it on your social networks, subscribe to the newsletter, and leave a comment you help me a lot. THANK YOU!&lt;/p&gt;

</description>
      <category>api</category>
      <category>wordpress</category>
      <category>php</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
