<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Raúl Cano</title><description>Self-taught dev. A chill guy who codes at home, hits the gym, and is passionate about indie hacking and the indie web.</description><link>https://raulcano.dev/</link><language>es</language><atom:link href="https://raulcano.dev/feed.xml" rel="self" type="application/rss+xml"/><item><title>Tailwind is trash, but I still use it</title><link>https://raulcano.dev/posts/tailwind-is-trash-but-i-still-use-it/</link><guid isPermaLink="true">https://raulcano.dev/posts/tailwind-is-trash-but-i-still-use-it/</guid><pubDate>Thu, 02 Apr 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I can&apos;t say much more than what the title already tells you I&apos;m only writing this while getting frustrated during a style maintenance session, because that&apos;s when, and only then, Tailwind becomes a nightmare.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Using Tailwind makes development incredibly fast, and these days even more so with component libraries like Shadcn. Same goes for AI it&apos;s way easier since the number of files to read and write is cut in half.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The truth is, nobody wants to spend a single extra minute writing CSS to keep things tidy and clean, especially when you don&apos;t even know if the project is going to be successful. So let&apos;s iterate faster with Tailwind and don&apos;t get me wrong, I&apos;m the first one to take this approach. At the same time though, I know what a nightmare it becomes when, six months later, you have to go back and maintain or fix any style. If you say you can read a whole component with all its Tailwind classes and have no problem with it, you have a superpower, dude. And it&apos;s not just that what about when you&apos;re trying to go from the browser to your code, looking for a specific component? You&apos;d inspect the page, click on that element, copy the class name, and pray you&apos;re the only component using that Tailwind class. With CSS, that same search is a confirmed headshot.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;We have a saying in Spain that perfectly defines what Tailwind is: &quot;Pan pa hoy, hambre pa mañana&quot; bread today, hunger tomorrow.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The good thing is, now with AI you can debug it way more easily. That&apos;s also part of why I keep using Tailwind.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Conclusion&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Use whatever makes you feel comfortable, and be aware of your time and capabilities. If you ask me, I&apos;d keep using Tailwind for its fast development, trade-off maintenance nightmare included. There is one case where I&apos;d go for pure CSS though if I have a project where I know from the start it&apos;ll last for years, with many other people working on it and a real guarantee of long-term success. But for now, since I never know when a project will actually take off, I&apos;m going to keep using Tailwind. Sadly.&lt;/p&gt;</content:encoded></item><item><title>The fear of not growing due to AI</title><link>https://raulcano.dev/posts/the-fear-of-not-growing-due-to-ai/</link><guid isPermaLink="true">https://raulcano.dev/posts/the-fear-of-not-growing-due-to-ai/</guid><pubDate>Thu, 01 Jan 2026 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So basically, I feel trapped in this AI world, and from what I can see on Reddit I’m not the only one, which makes me feel better tbh.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I started learning to code by myself pretty recently, around 2022, and if I’m not wrong, I tried ChatGPT for the first time as a coding helper in mid-2023. At that moment I had very basic knowledge, but enough to barely understand what the AI was throwing at me. Still, that felt like the first line of coke for an addict I was fascinated by how fast I was now able to solve problems.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Newbie bugs that took me days to solve were now done by AI in a matter of minutes.
However, the barrier was still there: there was no MCP, you needed to copy-paste from VS Code to the chat, so many times you still had to put in some effort to fix things.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now, with Cursor, Copilot, and so on, everything has changed drastically. These days, I sometimes spend the whole day writing either in English or Spanish but not really coding. I do read code, but it’s weird when I write more than four or five lines of code myself in a day.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So I need to ask: how good or bad is this behavior?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It doesn’t seem very good because you get lazy, but on the other hand you focus more on architecture, code cleaning tasks, reviewing, etc.
And was this really what I wanted when I started? I wanted to look like a hacker, not like a bored police officer staring at a security monitor.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It’s easy to say: “Then stop using AI tools and start doing some real coding yourself.” Yeah, sure but what if you work at a startup and everything is for yesterday? And not only that, but the whole market has now adapted to the speed AI tools gave us. Nobody expects a new feature to take 2–4 weeks anymore, but 1–2 days.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Everything is going so fast that you simply can’t stop and say, “Okay, I will change my habits so even if I’m slower, my coding skills will grow.”
Well, maybe just maybe you can do that in your free time, but even then you feel stupid going that slow when you know that with a simple prompt everything is done.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;What do you think? What can we, the new developers, do to keep growing our knowledge without losing that AI speed?&lt;/p&gt;&lt;figure class=&quot;zenex-cms__image-figure&quot;&gt;&lt;img src=&quot;https://pub-8d1a439ea0404f8f8d739f171ae8e8a6.r2.dev/blogs/cmi8nekhq000101n9ym0dfztg/1767453065740-rdbonz7zgk.png&quot; alt=&quot;&quot; class=&quot;zenex-cms__image&quot; /&gt;&lt;/figure&gt;</content:encoded></item><item><title>Infinite Bugs</title><link>https://raulcano.dev/posts/infinite-bugs/</link><guid isPermaLink="true">https://raulcano.dev/posts/infinite-bugs/</guid><pubDate>Mon, 03 Nov 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Do you know someone with 0 bugs in their app?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Probably 0 is being perfect, and perfection does not exist. I will ask again:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Do you know someone running an app where the bug tickets are less than 5% of the total tickets?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Seriously, because I don&apos;t, and I would love to know how they do it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Typing everything helps with that, we already do that. Also, writing tests, which I should start doing, but still, bugs appear all the time.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It reminds me of that mole game where you have to hit the mole when it appears, but when you hit it, another one appears somewhere else, and you never end.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Unless you throw the game out the window.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I&apos;m not that long in this market, but I have the feeling that bugs are infinite.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I&apos;ve read a couple of times that bugs are part of the journey. You have to co-live with them, and at some point, you can become friends with them or go crazy because they are not going anywhere.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Bugs are like colds, you need them from time to time to realize how great it is to be healthy.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And solving them feels like a hit of dopamine, but oh surprise, you went bald before that dopamine hit you while trying to solve it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Ok, ok...&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Do you have bugs?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;This is a test&lt;/p&gt;</content:encoded></item><item><title>Conversación con mi abuela</title><link>https://raulcano.dev/posts/conversacion-con-mi-abuela/</link><guid isPermaLink="true">https://raulcano.dev/posts/conversacion-con-mi-abuela/</guid><description>Historias de mi bisabuelo y reflexiones</description><pubDate>Thu, 25 Sep 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Anoche subí a cenar a casa de mis abuelos, aprovechando que estoy estos días por mi pueblo. Surgió una de esas conversaciones con mi abuela que te hacen reflexionar, ella se sentó al lado de mí despues de cenar y empezó a contarme historias sobre mi bisabuelo, su padre. Todo sin mucho guion ni orden cronológico.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Historias de antes&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;El padre de mi abuela, antes de tener a mi abuela, estuvo en la Guerra Civil, lo enviaron a Zaragoza. Estando por allí, un día, subiendo una caja por la montaña con un compañero, en un momento se dio cuenta de que la caja pesaba bastante más; cuando se giró para ver a su compañero vio que le habían volado la cabeza. Y sí, podría haber sido él y no su compañero, y no haber nacido mi abuela.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Más tarde, en Zaragoza, le capturaron como prisionero de guerra, y una noche se escapó. Tuvo que cruzar el río Ebro, y de tanto frío se le empezó a pudrir el gemelo, y tuvo esa marca en la pierna toda su vida.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Cuando regresó a mi pueblo, ya después de tener a mi abuela, hacía todos los días uno o dos viajes en bicicleta a un pueblo de al lado. Está a unos 20 km, unos 30 minutos en coche con las carreteras actuales. Iba para comprar sacos de harina, echarlos a la bici y volver para que su mujer (la madre de mi abuela) hiciera pan para vender o cambiar por otros alimentos.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Tenían una casa de campo en las afueras, allí apenas tenían para comer, y no suficiente con eso, policías y militares de la zona a veces pasaban por su casa para coger (o robar) los pocos alimentos u aceite que pudieran tener. Mi abuela me contaba cómo hizo un agujero en el suelo donde tenían las mulas para poder esconder el aceite cuando vinieran los guardias.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Mi abuela, durante la infancia, solo tuvo un juguete, le regalaron una muñeca vieja de cartón e inocente de ella, como vio que la muñeca tenía los mofletes muy pintados, la metió al agua de las mulas y, al ser de cartón, se desmenuzó en pedazos. Se reía mientras me lo contaba.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;El presente&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;No hace falta decir que solo tenemos que comparar la cantidad de ventajas que tenemos hoy día para ver lo poco que apreciamos aquello que tenemos.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Hace tiempo estoy obsesionado en mejorar mi vida, y son pocos los momentos en los que paro y valoro lo que tengo. Todo es frenético, urgente, y con la sensación de tener unas anteojeras, como las que tienen los caballos, para que solo puedan ver la pista.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;No ha habido ninguna generación perfecta y sin problemas. Si tuviésemos más presente que problemas sociales, económicos o políticos van a existir siempre, de una u otra forma, creo que viviríamos más tranquilos. El humano no es perfecto y, por tanto, creo que nunca va a existir una generación perfecta.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Antes podías comprar una casa en 3-4 años, pero te faltaba el pan y no tenías coche ni podías viajar, y trabajabas en la vendimia. Ahora no te puedes comprar una casa, no te falta el pan, puedes viajar y trabajas en casa.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Y no estoy diciendo que te tengas que conformar, para nada, soy el primero que se considera ambicioso; te hablo de poder vivir con más tranquilidad, teniendo en cuenta lo que está en tu mano para cambiar a corto y medio plazo y lo que se escapa de tu control, sabiendo que no va a existir un tiempo en el que todo sea perfecto.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Conversaciones como esta no tienen precio, cuando alguien muere no solo muere la persona, sino toda la historia de esa persona. Te dejan pensativo, reflexivo, y mis habilidades amateurs de escribir no le hacen justicia a conversaciones o historias como esta, pero quería dejarlo plasmado en este blog para recordarlo.&lt;/p&gt;</content:encoded></item><item><title>I joined Salescaling &lt;3</title><link>https://raulcano.dev/posts/join-salescaling/</link><guid isPermaLink="true">https://raulcano.dev/posts/join-salescaling/</guid><pubDate>Wed, 20 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s November 2024, I was chilling at home while listening to a podcast, a spanish podcast called Spicy4tuna one of my favorite, and in that episode they went to Lanzadera, a spanish startup accelerator.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;They interviewed four startups that were part of Lanzadera, and one of them was Salescaling, where they talked with Jon, the CEO of Salescaling. It was the chat I like the most among the four, the product he was presenting was interesting and useful, and Jon has a great charisma, even more when he was talking about his own product.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So I messaged them on LinkedIn, just a very casual and short message, one of those messages that nobody replies to.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And as I said no one replies to that message, until two weeks later, when I received an answer from Jon, just like a friend that forgets to reply to your message, he shared me his phone number, I was shocked, no one on LinkedIn gives their phone number, even more in the first message, and I loved that.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then I texted him on WhatsApp, a casual and nice chat, he liked my profile and suggested me to text his partner Luis, the CTO of Salescaling.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I texted Luis, and same as Jon, I felt him like texting with a friend, he said he liked my GitHub activity, and offered to have a meet, and ofcourse I accepted.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;From a podcast to a random message on LinkedIn, to a meet with the CTO of a startup. Life is funny.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Every single detail you do in life matters.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;If that day I didn&apos;t text them on LinkedIn, I would not be here today.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;If I haven&apos;t heard that podcast, I would not be writting this post.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Ok, so I was in the meet with Luis, and at first I didn&apos;t know if that was an interview or just a chat, but I was excited. It&apos;s funny that we talked for an hour about life, and the last half hour he introduced me to the product and some technical stuff, and god damn he was good at explaining, and at coding aswell.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then he told me: &quot;Raúl I want you to join Salescaling at some point&quot;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Inside of me I was like: &quot;Hell yeah, while dancing Danza Kuduro&quot;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I loved these guys, I loved the product, of course I have to join.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then he explained me what their roadmap was, they were about to enter a seed round, and planned to hire more people.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;We ended up seeing each other every week talking about the product, about the company, and many other things, and so we become friends and colleagues after many hours of online meets.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And the story is quite long, like a mexican novel, but eventually I received the offer.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now is time to learn every corner of the product and put in the work to make it a success, see how this project grows.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;[https://salescaling.com](https://salescaling.com)&lt;/p&gt;</content:encoded></item><item><title>SQL</title><link>https://raulcano.dev/posts/sql/</link><guid isPermaLink="true">https://raulcano.dev/posts/sql/</guid><description>My SQL notebook</description><pubDate>Tue, 19 Aug 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;SQL query:&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;- SELECT - FROM - WHERE - GROUP BY - HAVING - ORDER BY&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Sweaty feet will give horrible odors.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Order of execution:&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;1. FROM 2. WHERE 3. GROUP BY 4. HAVING 5. SELECT 6. ORDER BY&lt;/p&gt;</content:encoded></item><item><title>Fetching data in Next.js. Server actions vs server functions vs API Routes</title><link>https://raulcano.dev/posts/fetch-in-next-the-good-way/</link><guid isPermaLink="true">https://raulcano.dev/posts/fetch-in-next-the-good-way/</guid><pubDate>Wed, 11 Jun 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Summary&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;| Feature | Server Actions | Server Functions | API Routes | |---------|----------------|------------------|------------| | **Cache data by default** | ❌ | ❌ | ❌ | | **Secure by default** | ❌ | ❌ | ❌ | | **Run in parallel** | ❌ | ✅ | ✅ | | **Public endpoints** | ❌ | ❌ | ✅ | | **Request method** | POST | GET | GET | | **Client-side execution** | ✅ | ❌ | ✅ | | **Server-side execution** | ✅ | ✅ | ✅ | | **React-query or SWR** | ✅ | ❌* | ✅ | | **Clean code** | ✅ | ✅ | ❌* |&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;#### React-query or SWR: Means that you can use libraries like react-query or SWR to cache the data in the client side, among other things. You can use the cache() function in the server side, for the server functions, but you won&apos;t be able to use it in the client side, and it doesn&apos;t have as many features as react-query or SWR.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;#### Clean code: If I choose to use API Routes, I would use tRPC to centralize the logic and have a cleaner codebase. But I would lose the public endpoints.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Why fetching data with server actions is not the right way&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Next.js introduced server actions in version 14. And until today, in my opinion, even though I love them, it seems not even the Vercel team knows exactly the best way to use them. It looks like an experiment (a good one, but still an experiment) to see how developers will use them.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The point is that all server actions are POST requests. They were mainly designed for mutation operations, but you can still fetch data from a POST request, but you won&apos;t be able to cache this data.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I dug deeper into this while building [dopost.co](https://dopost.co). The problem was that after visiting the same page you visited before, you could see another fetch to get the same data, which means the UX experience is slower, not scalable, and causes high consumption of resources.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And at the same time they won&apos;t run in parallel, so forget about fetching several data sources expecting to get a faster response.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;However, I realized I could use `SWR` or `react-query` to cache this data gathered by the server action since server actions can be used on the client side and those libraries also run on the client side. But still, we&apos;re still fetching the data sequentially and with a POST request.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;After reading some Next.js docs, watching some videos plus some threads on Reddit and Peerlist, I found out the following:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The approach for fetching data in Next.js that Next.js wants us to follow is using server functions in the server components and passing it through the props to the client components. No fetching with server actions. No fetching with API Routes.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;```tsx //page.tsx import { getPosts } from &quot;@/server/queries/getPosts&quot;; // Server function&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;export default function Home() {   const posts = getPosts();&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;return (     &lt;div&gt;       &lt;h1&gt;Posts&lt;/h1&gt;       &lt;ul&gt;         {posts.map((post) =&gt; (           &lt;li key={post.id}&gt;{post.title}&lt;/li&gt;         ))}       &lt;/ul&gt;     &lt;/div&gt;   ); } ```&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;```tsx //server/queries/getPosts.ts // NO &quot;use server&quot; here &lt;---------&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;import { cache } from &quot;react&quot;; import { db } from &quot;@/server/db&quot;;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;export const getPosts = cache(async () =&gt; {   const posts = await db.query.posts.findMany();   return posts; });&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;```&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Basically they want you to always process the data on the server side, fetching it on the server then passing it to the browser.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;My opinion&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Even though this is the approach recommended by Next.js, I don&apos;t really like it. Also, the fact of having a framework with different approaches to achieve the same goal depending on the Next.js version is not a good thing and doesn&apos;t make me trust the framework. Don&apos;t get me wrong, I love Next.js you can ship projects super fast and it&apos;s not difficult to learn, plus you can have all the backend logic in the same place, which I think is perfect for an MVP.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;If you ask me, I would use tRPC to handle all the fetching and mutation logic in order to centralize the logic and have a single source of truth. Otherwise you&apos;d be dealing with server actions for the mutations and server functions plus API Routes for the fetching. And yeah, I said tRPC, because in my opinion the way API routes look in your code looks very messy and ugly when it grows, since you have to create one folder for each API.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And this goes to another point: should I use Next.js since I&apos;m avoiding their principles? Should I just use React?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Well, I&apos;m still having this doubt, but the fact of not needing to create a separate backend and how easy it is to handle routes in Next.js is a big plus.&lt;/p&gt;</content:encoded></item><item><title>Embrace AI or be left behind</title><link>https://raulcano.dev/posts/embrace-ai-or-be-left-behind/</link><guid isPermaLink="true">https://raulcano.dev/posts/embrace-ai-or-be-left-behind/</guid><description>Have you ever felt bad about using AI? Me too.</description><pubDate>Wed, 30 Apr 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Feeling bad about using AI&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s September 2024, I&apos;m sitting in my setup developing a new side project. I&apos;m using ChatGPT to help me with the development. And it&apos;s insanely crazy.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I have no much free time to work on side projects. But this is a game changer.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Things you would spend weeks or months to do, with AI you can do it in hours or even minutes, whether you are building your new feature that nobody asked for, solving a problem, doing research or debugging.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You are faster than ever.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You are able to do more things than ever.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Man can now do more than one thing at the same time.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;*But then, you start to feel bad about it.*&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You start to feel guilty for using AI to do things that you could do manually.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You think that you are not being creative enough.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;That you are not learning.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You are not good enough.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Great, the impostor syndrome is over 9000.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I have been there.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;We have passed through here&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;When the internet was born, we were scared. People said that it would make us lazy or even dumb, and here we are, driving autonomous cars, ordering food, buying things from the other side of the world, talking to anyone in the world in a matter of seconds, and million other things.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;More advanced than ever, faster than ever.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now we are passing through the same thing with AI. It&apos;s something new, we are just starting to understand how to use it, building new tools around it, and since we are animals, we are scared of the unknown.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;AI it&apos;s here to stay. It&apos;s not going away, no matter how much you resist it, and even worse if you resist it, you are the one who will be left behind. Just imagine yourself back in the school saying &quot;No teacher, I&apos;m not going to use the calculator as my colleagues, I&apos;m going to do it manually 🤡&quot;. Because you are the smartest guy right? Or at least that&apos;s what you want to believe.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s not only fear the unknown but also the lack of self-esteem, and the seek for approval from others.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Embrace AI&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I&apos;m not saying AI is the answer to everything, in fact, it&apos;s not. At least not for now. If you are dumb, you are going to be a dumb with AI. It&apos;s just a tool, a great tool but a tool nonetheless.  You need to know what AI is doing, the architecture and patterns it&apos;s using, you don&apos;t want to be one of these vibecoders who don&apos;t even know what is a variable, he might be able to lauch an MVP, in the best case scenario, but it&apos;s going to be funny.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;All this time I&apos;ve been feeling bad about using AI, with such a mental battle. But you know what? I surrendered, and I can explain you my reasons and you may have a different opinion of course, but this is my blog so let&apos;s go to the point.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Ask yourself the next super simple question:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;👉 What is your goal?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;1. 1- Gaining a trophy to the smartest guy in the world and have 0$ and no time 2. 2- Have more free time to enjoy your life, solve problems faster and get more money&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I don&apos;t know about you, but I choose the second one. Maybe if you are a vain person the first one is for you.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;But again of course, learn at least what a variable is.&lt;/p&gt;</content:encoded></item><item><title>A Wild Lambda Appeared!</title><link>https://raulcano.dev/posts/lambda-serverless/</link><guid isPermaLink="true">https://raulcano.dev/posts/lambda-serverless/</guid><description>Lambda... Lambda... What is that?</description><pubDate>Thu, 06 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Sometimes I hear about concepts I have no idea about, and I love that feeling.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s like &quot;Let&apos;s go figure out what that is!&quot;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Today I heard about lambda while talking about backend development.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;My mind was like &quot;A wild rare Pokemon has appeared! It&apos;s Lambda!&quot;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;A - Fight    B - Run away&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I pressed A. Let&apos;s find out what this new term is&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;What is this pokemon Lambda?&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;First, let&apos;s clarify that &quot;Lambda&quot; is just the name AWS gives to their &quot;serverless functions&quot;. Every cloud provider has their own version, Azure calls them &quot;Azure Functions&quot;, Vercel calls them &quot;Serverless Functions&quot;, Cloudflare calls them &quot;Cloudflare Workers&quot; and so on.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Imagine your server, the one you use when deploying your apps. It&apos;s running constantly whether you have requests or not, which means you&apos;re going to be charged for its consumption (resources, compute time, etc.) even when it&apos;s chilling.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;With the Lambda approach, that changes. Instead, you have a collection of functions that are only triggered on-demand.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;&gt; The Lambda service runs your function only when needed and scales automatically. You only pay for the compute time that you consume—there is no charge when your code is not running.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;—[AWS Doc](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html)&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Traditional Server (like NestJS):&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;// Look, this server is always running somewhere
@Controller(&apos;documents&apos;)
export class DocumentController {
  @Post(&apos;process&apos;)
  async processDocument() {
    // Yes, this code runs only when someone hits the endpoint
    // But hey, the server is still alive and kicking all the time!
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The annoying part? If nobody&apos;s using your app, you&apos;re still paying. And if suddenly everyone wants to use it, you need to upgrade the whole machine! Now, Lambda functions are different:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;There&apos;s no server running all the time - the function is just chilling, doing nothing. It only wakes up when someone needs it (like when they make a request). The cool part? You only pay for those few milliseconds it&apos;s actually doing something!&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;// This guy only exists when someone calls it
export const handler = async (event) =&gt; {
  // It does its job and then... poof! Disappears completely
}&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;A funny analogy woulf be:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;- Having a restaurant open 24/7 with chefs just waiting around (your NestJS server)&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;- Having magic chefs that appear ONLY when someone orders food (Lambda)&lt;/p&gt;</content:encoded></item><item><title>Server Actions in Next.js 15 to manage CRUD operations</title><link>https://raulcano.dev/posts/nextjs-15-server-actions-crud/</link><guid isPermaLink="true">https://raulcano.dev/posts/nextjs-15-server-actions-crud/</guid><description>My approach to handling CRUD operations in Next.js App Route</description><pubDate>Wed, 05 Feb 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I started building a large API layer and using TanStack Query, but then I realized it wasn&apos;t worth it nor a good approach for the Next.js App Router and for an MVP boilerplate, because Next.js App Router already provides built-in data fetching and caching through Server Components and Server Actions.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;After the Next.js 13 release, the approach to developing a Next.js application now focuses on Server Components and Server-Side Rendering (SSR), along with the introduction of Server Actions.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Server actions are server-side functions that process forms and data. They must be marked with &quot;use server&quot; and can be used on the server or the client side (via form actions or direct invocation).&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So instead of creating multiple endpoints in our routes and managing them with TanStack, fetch requests, useEffect, etc., we will manipulate the data using server functions, which reduces client-side complexity.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;That means we don’t need or shouldn’t use the TanStack library (some people also like to use a mix of both which can be a good approach) to avoid client-side load and should instead focus on the server, leveraging Next.js’s built-in data handling capabilities.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Here is an example of the structural approach we have taken: we have separated server actions from queries. Server actions are meant to be used in forms, while `queries don’t need to be marked with &quot;use server&quot;`, as doing so would disable Next.js&apos;s caching, which is crucial for performance.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;src/
├── services/
│   └── users/
│       ├── mutations.ts    // POST, PUT, DELETE operations with &apos;use server&apos;
│       ├── queries.ts      // GET operations without &apos;use server&apos;
│       └── types.ts        // User types
│
...&lt;/code&gt;&lt;/pre&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Caching clarification&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Yeah, you may be thinking, &quot;But why can&apos;t I just include the fetch logic within the &apos;use server&apos; directory, like server actions?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;&gt; Even though you can use server actions to fetch data, Next.js discourages it because it can only send a POST request. Instead, fetch the data from the server component and pass it down as props.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;— @Towel1355 on reddit&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Server actions are designed for mutations (creating, updating, or deleting data), while queries (data fetching) benefit from Next.js&apos;s built-in caching and revalidation.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Actually, if you inspect the page and check the network tab, you can see how the server actions are POST requests.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;// queries.ts
export async function getUser(id: string) {
  // This can be cached by Next.js
  const user = await prisma.user.findUnique({ where: { id } })
  return user
}&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;VS&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;// mutations.ts
&quot;use server&quot;
export async function getUser(id: string) {
  // This bypasses Next.js cache
  const user = await prisma.user.findUnique({ where: { id } })
  return user
}&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;&gt; Note: We only will need to create API routes when we need to work with thirds services&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Sources&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;- [Next.js Doc](https://nextjs.org/docs/app/building-your-application/data-fetching/server-actions-and-mutations#convention) - [Next.js Mutating](https://nextjs.org/learn/dashboard-app/mutating-data) - [What is the point of server actions?](https://www.reddit.com/r/nextjs/comments/1ad3q3h/what_is_the_point_of_server_actions/) - [Server Action in Next.js: What it is, How to Define Them, and What to Consider for Security](https://medium.com/@dev-journey/server-action-in-next-js-what-it-is-how-to-define-them-and-what-to-consider-for-security-8fc9f2e200e1#:~:text=Share-,Server%20Actions%20in%20Next.,improves%20app%20performance%20and%20scalability.)&lt;/p&gt;</content:encoded></item><item><title>Procrastination</title><link>https://raulcano.dev/posts/procrastination/</link><guid isPermaLink="true">https://raulcano.dev/posts/procrastination/</guid><description>You are procrastinating again.</description><pubDate>Fri, 24 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Procrastination is like a credit card with your future self.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;There is you sitting in front of your laptop, ready to take action, ready to work on your future.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;But BOOM! a &quot;How to become rich in 2025&quot; YouTube video shows up in your feed. And  guess what? You click on it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You check the clock, it has been 2 hours since you fell into the rabbit hole of YouTube.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now it&apos;s time to eat, sleep or do something else.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You have wasted your time again.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You have procrastinated again.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Videos that promise to make you become something or give tips to achieve something are not the problem.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The problem is you.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Videos that give you dopamine then drain your energy to do what really matters.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;But how does procrastination work?&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s something normal, we all do it. We have to live with it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The loop is something like this:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;1- You have a long/hard task to do.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;2- You feel overwhelmed by the task.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;3- The brain&apos;s natural reaction then is to generate adrenaline and cortisol.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;4- The frontal part of the brain gets saturated, the part in charge of making decisions.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;![Procrastination](/blog/procrastination.svg)&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;&lt;br/&gt;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Faced with the task, we choose to postpone, to procrastinate on the task as a defense, since that will save us energy.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So then you end up doing something else that gives you instant gratification, like watching a video, eating, or sleeping.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;How do I deal with it?&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Actually, I don&apos;t have the key, sorry. I&apos;m still struggling with it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;But what works for me so far is to not negotiate with my brain and just take action.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Once you know the previous theory and why that happens, you can anticipate it and act accordingly.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Or at least try to.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In your brain, you usually have two characters living there, they are like the politicians of your body, discussing all the time what are the &quot;best&quot; decisions.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;One is rational, the other is emotional.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The emotional one will always side with natural instincts, like procrastination.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The rational one will always side with long-term benefits, like working on your future.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So I just try to give more attention to the rational one. Even though sometimes I follow the emotional one&apos;s instructions, I try to at least be conscious of it.&lt;/p&gt;</content:encoded></item><item><title>Tough Times</title><link>https://raulcano.dev/posts/tough-times/</link><guid isPermaLink="true">https://raulcano.dev/posts/tough-times/</guid><description>Life is not easy, but it is what it is</description><pubDate>Sun, 12 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;A Personal Reflection&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I don&apos;t know where to start, these last weeks have been tough. Life in Lisbon is not easy, even though I got my dream job and I don&apos;t hate Mondays anymore. It&apos;s tough because it&apos;s frustrating, it&apos;s frustrating because I feel I&apos;m doing everything I should be doing to build a good future, but the results take time to come.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I keep studying after work, I do side projects in my free time, go to the gym, run, don&apos;t drink alcohol, read books... Well, the common blueprint from one of these mainstream books.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So I&apos;m having an internal discussion with two parts of my mind. The first is saying:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;&quot;I&apos;m sacrificing so many enjoyable things but you&apos;re still living in a crappy shared apartment. I can&apos;t eat as many sweets as I&apos;d like, I can&apos;t enjoy a late party, but in exchange for what?&quot;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;On the other hand, the other part says:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;&quot;You are doing well. Good things take time to arrive. You can&apos;t lose your focus right now, you have to fight and get out of that negative spiral that can pull you away from your goals.&quot;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So yeah, I&apos;ll try to listen to what that last part says. My body can suffer in the environment, but my mind must be at peace outside of myself because I&apos;m not the money I have in my bank account, I&apos;m not the phone or clothes I have.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Signed, a random Spanish guy who lives in Portugal.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Is there someone reading this? I don&apos;t know, but it feels good to write.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Whatever, let&apos;s focus.&lt;/p&gt;</content:encoded></item><item><title>My First NPM Package got 3,000 Downloads in a Week</title><link>https://raulcano.dev/posts/npm-package-creator-journey/</link><guid isPermaLink="true">https://raulcano.dev/posts/npm-package-creator-journey/</guid><pubDate>Thu, 09 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;React GitHub Dots - My NPM Journey&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;A year ago, I was creating my first blog with Astro, and I needed something to organize the blogs into pages. So I started searching online to see if Astro had anything to solve this, and Astro didn&apos;t have anything built-in.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Until I randomly found a blog talking about an npm package for Astro to manage blog pagination. The creator was [Phil Nash](https://philna.sh/). Months later, I went to a talk he gave in Berlin at the WeAreDevelopers World Congress.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The internet is beautiful, and the community is beautiful too. Someone who also needed a pagination component not only created it but shared it with the community.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Every day we use things made by people without thinking about it, but that day it caught my attention so much that I went to learn more about Phil Nash. I had never looked up who the author of an NPM package was before.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;After this, I had the idea to create an NPM package too. I had no idea where to start - it seemed like something only hackers could do.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;However, now even though I don&apos;t have much experience, we have great AI tools plus the internet itself that explain the process almost like having a senior developer next to us.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And last weekend the idea came: I was creating a new portfolio and thought it would be cool to add the GitHub contributions graph, the one with the green dots.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So why not create it not just for me but for anyone who wants to use it?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Boom! Done [Green Dots](https://green-dots.vercel.app/) created, and in less than a week it already has +3,000 downloads on NPM.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The internet is beautiful! And again, thanks to Phil for the inspiration he gave me that day.&lt;/p&gt;</content:encoded></item><item><title>How to set up Vite in a WordPress theme</title><link>https://raulcano.dev/posts/setting-up-a-compiler-in-wordpress/</link><guid isPermaLink="true">https://raulcano.dev/posts/setting-up-a-compiler-in-wordpress/</guid><description>A step-by-step tutorial for integrating Vite as a modern build tool in WordPress</description><pubDate>Mon, 21 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Compiler vs Bundler&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Let&apos;s briefly figure out some doubts I had between the difference of a compiler and a bundler. In the past we were using Babel and Webpack, with Babel you can compile your JavaScript code and Webpack will bundle it into a single file or multiple files. But now I&apos;m using Vite as a bundler and compiler, since it covers both functionalities and it&apos;s faster than Webpack.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Compiler&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;A JavaScript compiler allows you to write code using the latest version of JavaScript (ECMAScript 6) and it will transform or compile it to a version that is compatible with most browsers.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s primarily configured with a file or in your build tool (Vite, Rollup, Gulp, etc.).&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Example of a code written in modern JavaScript ES6:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;const greet = (name) =&gt; {
  console.log(`Hello, ${name}!`);
};&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;After it compiles the code, it will look like this (ES5):&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;var greet = function(name) {
  console.log(&apos;Hello, &apos; + name + &apos;!&apos;);
};&lt;/code&gt;&lt;/pre&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Bundler&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The purpose of a bundler is to group or bundle all your assets (JavaScript, CSS, etc.) into a single file or multiple files that can be loaded by the browser.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It&apos;s primarily configured with a file or in your build tool (Vite, Webpack, Rollup, etc.).&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Setting up Vite in WordPress&lt;/h2&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Creating the package.json file&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You can simply run `npm init -y` to create a `package.json` file with default values.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Add the devDependencies in your package.json&lt;/h3&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;npm install --save-dev vite sass&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Or you can add them to devDependencies in your package.json file.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&quot;devDependencies&quot;: {
    &quot;vite&quot;: &quot;^5.4.9&quot;,
    &quot;sass&quot;: &quot;^1.80.3&quot;,
  }&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then run `npm install` to install the dependencies.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;If you are using VSC you can also install the extension `Version Lens` to see or update the versions of your dependencies.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Add the scripts in your package.json&lt;/h3&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&quot;scripts&quot;: {
    &quot;start&quot;: &quot;vite build --watch&quot;,
    &quot;dev&quot;: &quot;vite&quot;,
    &quot;build&quot;: &quot;vite build&quot;
  }&lt;/code&gt;&lt;/pre&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Create the vite.config.mjs file&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Inside the root of your project, create a `vite.config.mjs` file and add the following code:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;//vite.config.mjs
import { defineConfig } from &apos;vite&apos;;

export default defineConfig({
  // Vite configuration options
});&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In the configuration file, you can define various options for your project, like the root directory and build options.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The root directory is where your JavaScript files are located, and the build options define the output directory and the input files.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Fill the entry and output variables in Vite&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Change the paths according to your project. In Vite, you don&apos;t explicitly define entry and output paths like in Webpack. Instead, you set the root and build options.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;//vite.config.mjs
import { defineConfig } from &apos;vite&apos;;
import { resolve } from &apos;path&apos;;

// Get the main.js where all your JavaScript files are imported
const JS_FILE = resolve(&apos;src/scripts/main.js&apos;)

// Define where the compiled and minified JavaScript files will be saved
const BUILD_DIR = resolve(__dirname, &apos;dist&apos;);

export default defineConfig({
  build: {
    assetsDir: &apos;&apos;, // Will save the compiled JavaScript files in the root of the dist folder
    manifest: true, // Generate manifest.json file (for caching)
    emptyOutDir: true, // Empty the dist folder before building
    outDir: BUILD_DIR,
    rollupOptions: {
      input: JS_FILE,
    },
  },
});&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;With this configuration, Vite will compile and bundle your JavaScript files into the `dist` directory. But not the CSS.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Folder structure with JavaScript files&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;At this point we should have something like this:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;mytheme/
├── dist/
│   ├── main-AD2AS.js
│   └── .vite/
│       └── manifest.json
├── src/
│   └── scripts/
│       ├── main.js
│       ├── woo/
│       └── components/
├── node_modules/
├── package.json
├── package-lock.json
├── functions.php
├── vite.config.mjs
└── style.css&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Enqueue JavaScript in functions.php&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&lt;?php
// ... other code
add_action(&apos;wp_enqueue_scripts&apos;, function(){
    $manifestPath = get_theme_file_path(&apos;dist/.vite/manifest.json&apos;);
    
    // Check if the manifest file exists and is readable before using it
    if (file_exists($manifestPath)) {
        $manifest = json_decode(file_get_contents($manifestPath), true);
        
        // Check if the file is in the manifest before enqueuing
        if (isset($manifest[&apos;src/scripts/main.js&apos;])) {
            wp_enqueue_script(&apos;mytheme&apos;, get_theme_file_uri(&apos;dist/&apos; . $manifest[&apos;src/scripts/main.js&apos;][&apos;file&apos;]));
        }
    }
});
?&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Building the CSS&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;For this part we don&apos;t need to touch the `vite.config.mjs` file any more. We just need to add the CSS files to the `main.js` file.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;// src/scripts/main.js

/**
 * Main JS file for Cartify Child
 * 
 * Import the main css file
 * Import all the JavaScript files that are needed for the theme.
 */

// Import the main CSS file
import &apos;../styles/main.scss&apos;

// Build the main JS file
// ... other js files imports&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In our case we need to create the `main.scss` file in the `src/styles/` directory. There you will add or import all the other CSS files that you need.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Folder structure with CSS files&lt;/h3&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;mytheme/
├── dist/
│   ├── main-something.js
│   └── .vite/
│       └── manifest.json
├── src/
│   ├── scripts/
│   │   ├── main.js
│   │   ├── woo/
│   │   └── components/
│   └── styles/
│       ├── main.scss
│       └── general/
├── node_modules/
├── package.json
├── package-lock.json
├── functions.php
├── vite.config.mjs
└── style.css&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Enqueue CSS in functions.php&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And as we did with the JavaScript files, we need to enqueue the CSS file in the `functions.php` file. We just need to update the previous code to enqueue the CSS file.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;add_action(&apos;wp_enqueue_scripts&apos;, function(){
    $manifestPath = get_theme_file_path(&apos;dist/.vite/manifest.json&apos;);
    
    // Check if the manifest file exists and is readable before using it
    if (file_exists($manifestPath)) {
        $manifest = json_decode(file_get_contents($manifestPath), true);
        
        // Check if the file is in the manifest before enqueuing
        if (isset($manifest[&apos;src/scripts/main.js&apos;])) {
            wp_enqueue_script(&apos;mytheme&apos;, get_theme_file_uri(&apos;dist/&apos; . $manifest[&apos;src/scripts/main.js&apos;][&apos;file&apos;]));
            // Enqueue the CSS file
            wp_enqueue_style(&apos;mytheme&apos;, get_theme_file_uri(&apos;dist/&apos; . $manifest[&apos;src/scripts/main.js&apos;][&apos;css&apos;][0]));
        }
    }
});&lt;/code&gt;&lt;/pre&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;My .vite/manifest.json file&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Just for your curiosity, this is how my `manifest.json` file looks like:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;{
  &quot;src/scripts/main.js&quot;: {
    &quot;file&quot;: &quot;main-BL027S3L.js&quot;,
    &quot;name&quot;: &quot;main&quot;,
    &quot;src&quot;: &quot;src/scripts/main.js&quot;,
    &quot;isEntry&quot;: true,
    &quot;css&quot;: [
      &quot;main-BLUr3EH8.css&quot;
    ]
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Running Vite&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now you can run Vite with the following command:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;npm run start&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Conclusion&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;This is how you can set up Vite in a WordPress theme. It&apos;s a bit different from Webpack, but it&apos;s faster and easier to configure. You can also use Vite for many other projects.&lt;/p&gt;</content:encoded></item><item><title>Next Auth error: To confirm your identity, sign in with the same account you used originally.</title><link>https://raulcano.dev/posts/next-auth-error-to-confirm-your-identity-sign-in-with-the-same-account-you-used-originally/</link><guid isPermaLink="true">https://raulcano.dev/posts/next-auth-error-to-confirm-your-identity-sign-in-with-the-same-account-you-used-originally/</guid><description>How to fix the &apos;To confirm your identity, sign in with the same account you used originally&apos; error in Next Auth</description><pubDate>Sun, 20 Oct 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Next.js 14&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I encountered this error when I was building my first Next.js project with Next Auth, and as I was getting crazy with it, I decided to write to don&apos;t forget it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The thing is that I wanted to use a `email provider` and `Google provider` or any other, at the same time. I didn&apos;t understand why this error was happening, and there were no clear answers on the internet. It may be something easy for someone with more experience, but...&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Understanding the error&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In the case I&apos;m mentioning, the error is due to the fact we want the user to be able to sign in with Google and with an email provider. And for security reasons, Next Auth wants to prevent this.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;But why?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Well lets imagine that a user signs in with the Google provider, he will have is own account and blablabla.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now what if the same user signs in with the email provider? He will have another account, and this is not what we want. We want the user to have only one account, no matter how he signs in.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;But Next Auth doesn&apos;t Know whether the user is the same or not. So it throws this error.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Solution&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The solution is to add an option to allow this behavior. This is done by adding the `allowDangerousEmailAccountLinking` option to the Google provider.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Here is the code:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;// @/lib/auth.ts in my case

  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID as string,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
      allowDangerousEmailAccountLinking: true,
    }),
    EmailProvider({
      // Your email provider configuration
    }),
  ],&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And ta da!&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;[Next Auth documentation](https://next-auth.js.org/configuration/providers/oauth#allowdangerousemailaccountlinking-option)&lt;/p&gt;</content:encoded></item><item><title>Setting up MongoDB locally in a Next.js project [Mac]</title><link>https://raulcano.dev/posts/run-mongodb-locally-in-nextjs/</link><guid isPermaLink="true">https://raulcano.dev/posts/run-mongodb-locally-in-nextjs/</guid><description>How to install MongoDB locally and add the MONGODB_URI to a Next</description><pubDate>Sun, 25 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Next.js 14.2.6 | MongoDB 7.0&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;1. Install MongoDB with Homebrew&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;brew tap mongodb/brew&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;brew install mongodb-community@7.0&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;2. Start MongoDB service&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;brew services start mongodb-community@7.0&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;3. Check MongoDB service status&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;brew services list&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Here you should have a table like this with the status `started`:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Name              Status  User File
mongodb-community started user ~/Library/[...]/mongodb-community&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;4. Connect to MongoDB&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;mongosh&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now you can see the MongoDB shell prompt:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Current Mongosh Log ID: 1234567890
Connecting to: mongodb://
Using MongoDB: 7.0.0&lt;/code&gt;&lt;/pre&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;4.1. Show databases&lt;/h3&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;show dbs&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;By default you should see some databases like `admin`, `config`, `local`, `test`.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Mongo places your data in the `test` (`test&gt;`) database  by default. If you want to create a new database, you can do it with the `use` command + the name of the database.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;5. Create a new collection&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;We are going to test the connection in the terminal with a new collection called `myNewCollection`.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;db.createCollection(&apos;myNewCollection&apos;)&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;6. Insert a new document&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;db.myNewCollection.insertOne({ name: &apos;Raul&apos;, age: 30 })&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;7. Query all documents&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;db.myNewCollection.find()&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;`Note:` Keep this in mind before going to the next step&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;- You can have multiple databases in MongoDB. - Each database can have multiple collections. - Each collection can have multiple documents.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The structure is like this:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Database
  Collection
    Document&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The `Database` is the top-level container for our data. It is the container for collections. The `Collection` is a group of documents. The `Document` is a set of key-value pairs that you might be manipulating them with mongoose in your Next.js project.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In the terminal when you run `mongosh` normally you are in the `test` database, thats why you see the `test&gt;` prompt. So then all the commands you run are in the `test` database.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;So when you run `test&gt; db.myNewCollection.find()` you are querying the `myNewCollection` collection in the `test` database.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;---&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;8. Add the MongoDB URI to Next.js .env.local file&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Ok so now we have MongoDB installed and running on our Mac. We need to add the MongoDB URI to our Next.js project.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;mongosh&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You will see the MongoDB shell prompt of the step 4. `copy` the &quot;Connecting to&quot; value.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Connecting to: mongodb://127.0.0.1:27017/...&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Go to Next.js and paste it in your `.env.local` file in your Next.js project.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;MONGODB_URI=mongodb://127.0.0.1:27017/...&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;9. Test the connection&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You can forget the previous collection we created in the terminal.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Run your Next.js project with `npm run dev` and test the connection with MongoDB, you first need to submit a form or make a request to the database, like registering a new user.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then in the terminal:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;```bash   mongosh&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Ensure you are in the correct database and collection in our case `test` and `users`:&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;use test&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Now check the database and collection `users`:&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;db.users.find().pretty()&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;Here we are inside the DB `test` and the collection `users`. You should see the new user you just registered.

Make sure you are in the correct database and collection otherwise you will not see the new user.

---

## How to Stop MongoDB service 
(Do not forget to stop the service when you are done)&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;brew services stop mongodb-community@7.0&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;`Reestart` MongoDB service:&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;brew services restart mongodb-community@7.0&lt;/p&gt;</content:encoded></item><item><title>Add a Custom Block Within the Core Navigation Block in WordPress</title><link>https://raulcano.dev/posts/add-block-to-navigation/</link><guid isPermaLink="true">https://raulcano.dev/posts/add-block-to-navigation/</guid><description>Step-by-step guide to add a custom block within the core navigation block in WordPress</description><pubDate>Mon, 12 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;`Note`: To follow along this you already know how to create a plugin custom block in WordPress 6.6. If you don&apos;t, you can check out the [official documentation](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/).&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;If you want to jump straight to the main point, see the 3 step [index.js](#3-add-the-block-to-the-navigation-block) file.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Introduction&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;By default in WordPress, you can&apos;t add a custom block within the core navigation block. Here I&apos;ll show you the key steps to add add your block within the core navigation block. Bear in mind that this is a simplified version of the process, we are not going to going to create a whole block from scratch, but rather add a custom block to the navigation block.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Block structure:&lt;/h2&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;wp-content/
└── plugins/
    └── my-plugin/
        ├── my-plugin.php
        └── block-example/
            ├── block.json
            ├── edit.js
            ├── editor.scss
            ├── index.js
            ├── render.php
            ├── script.js
            ├── style.scss
            └── view.js&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;1. Configure block.json&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;`block.json`:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;{
	&quot;name&quot;: &quot;my-plugin/block-example&quot;,
	&quot;version&quot;: &quot;0.1.0&quot;,
	&quot;title&quot;: &quot;Example Block&quot;,
	&quot;category&quot;: &quot;design&quot;,
	&quot;textdomain&quot;: &quot;my-plugin&quot;,
	&quot;description&quot;: &quot;Add the Example Block within the navbar&quot;,
	&quot;parent&quot;: [ &quot;core/navigation&quot; ], &lt;- Don&apos;t forget this
	&quot;attributes&quot;: {
		&quot;blockId&quot;: {
			&quot;type&quot;: &quot;string&quot;,
			&quot;default&quot;: &quot;&quot;
		}
	},
...Everything else
}&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;2. Register your block&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;`my-plugin.php`:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&lt;?php
/**
 * Plugin Name:       My Plugin
 * Description:       An exploratory My Plugin
 * Requires at least: 6.5
 * Requires PHP:      7.0
 * Version:           0.1.0
 * Author:            Raul Cano
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       my-plugin
 *
 * @package           my-plugin-block
 */

/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function my_plugin_block_example_init() {
	register_block_type( __DIR__ . &apos;/build&apos; );
}
add_action( &apos;init&apos;, &apos;my_plugin_block_example_init&apos; );&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;3. Add the block to the Navigation block&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;`index.js`:&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;import { registerBlockType } from &apos;@wordpress/blocks&apos;;

import &apos;./style.scss&apos;;
import &apos;./editor.scss&apos;;

import Edit from &apos;./edit&apos;;
import metadata from &apos;./block.json&apos;;

registerBlockType(metadata.name, {
	edit: Edit,
	icon: &apos;admin-site&apos;,
});&lt;/code&gt;&lt;/pre&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;/**
 * Make the Example Block available to Navigation blocks.
 *
 * @since 0.1.0
 *
 * @param {Object} blockSettings The original settings of the block.
 * @param {string} blockName     The name of the block being modified.
 * @return {Object} The modified settings for the Navigation block or the original settings for other blocks.
 */
const addToNavigation = ( blockSettings, blockName ) =&gt; {
	if ( blockName === &apos;core/navigation&apos; ) {
		return {
			...blockSettings,
			allowedBlocks: [
				...( blockSettings.allowedBlocks ?? [] ),
				&apos;my-plugin/block-example&apos;, // Change this to the actual block name in block.json
			],
		};
	}
	return blockSettings;
};
addFilter(
	&apos;blocks.registerBlockType&apos;,
	&apos;my-plugin-block-example-add-to-navigation&apos;, // Change this to a unique name for your filter.
	addToNavigation
);&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Conclusion&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The main file that allows us to insert a custom block inside the navigation block is `index.js`. This file is responsible for registering the block and adding the block to the navigation block. The `block.json` file is also important because it defines the block&apos;s metadata, including the parent block. Finally, the `my-plugin.php` file registers the block and its assets.&lt;/p&gt;</content:encoded></item><item><title>Should I go to a tech event if I&apos;m junior?: WeAreDevelopers 2024</title><link>https://raulcano.dev/posts/should-i-go-to-a-tech-event-if-im-junior/</link><guid isPermaLink="true">https://raulcano.dev/posts/should-i-go-to-a-tech-event-if-im-junior/</guid><description>I remember the first day I heard &apos;GitHub&apos;. What was that? Why was everyone always using that word? Is it so important?</description><pubDate>Sat, 20 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Attending WeAreDevelopers 2024&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;There I was, sitting in a chair in one of the talks at WeAreDevelopers 2024. I didn’t understand anything. But nothing at all, and next to me there was another guy:&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Me: Hey! What’s your name?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Him: Hey, I’m Valerio, and you?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;[...]&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Him: Wait, what? Just two months of work experience and you’re here listening to a talk about architecture?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Me: I’m curious hahah &lt;br&gt;&lt;br&gt;&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Even though I could think I have wasted the money as I didn’t understand pretty much everything, I prefer to think that attending the event is forcing me to raise my level of expertise, to achieve the knowledge that many of the people there have.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Not only that, which is true, but also retaining a bunch of unknown terms that I had no idea about until now. Now I just know that new term, that new technology. So when I arrive home, my lover ChatGPT is ready to answer tons of questions until I feel comfortable with the meaning of this new word.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Starting is hard, we all know. I remember the first day I heard “GitHub”. What was that? Why was everyone always using that word? Is it so important?&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Well, I remember I spent the whole afternoon asking ChatGPT and searching on Google about this black cat.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I’m not saying that you should go to every event you see, but if you have the opportunity to attend one, don’t hesitate. You will learn a lot, even if you don’t understand everything. You will be forced to learn, and that’s the best way to do it.&lt;/p&gt;</content:encoded></item><item><title>Resetting the Full-Site Editor in WordPress</title><link>https://raulcano.dev/posts/resetting-the-full-site-editor-in-wordpress/</link><guid isPermaLink="true">https://raulcano.dev/posts/resetting-the-full-site-editor-in-wordpress/</guid><description>Did you mess up your Full-Site Editor in your Local environment and now it&apos;s looks different from the Production site? Here&apos;s how to reset it.</description><pubDate>Fri, 12 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Imagine you are working with your team on a WordPress site, and you are using the Full-Site Editor to make changes to the site. But when you push those changes to the Production site, the Full-Site Editor looks different.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;To understand what is going on, let&apos;s first explain what the Full-Site Editor is in WordPress.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The Full-Site Editor is a new feature in WordPress that allows you to edit your entire site using blocks. It&apos;s a new way to build and customize your site without having to write code.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;But the changes you make in the Full-Site Editor are stored in the database&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And here is the problem: if you make changes in your Local environment, those changes will be stored in the database. And when you push those changes to the Production site, the Full-Site Editor will look different, simply because the database is different.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;To setup all the settings on the site, WordPress will first look into the database. If the settings are not there, it will use the settings from the theme in `theme.json`. And so `theme.json` is the key to reset the Full-Site Editor, as it is pushed, and committed to the repository.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;---&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Requirements&lt;/h3&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;You will need to have a git branch to see the changes, that will allows you to remove them at the end.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;1. Install Create Block Theme Plugin&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Install the plugin [Create Block Theme](https://wordpress.org/plugins/create-block-theme/) and activate it.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;This plugin allow us to add all the settings we&apos;ve made from the database to the `theme.json` file.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then go to Appearance &gt; Editor &gt; Click on the Full-Site Editor tab to open the settings of the Full-Site Editor. (Does not matter the desing you choose on the left side)&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;2. Export the settings&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;This will update the `theme.json` file with all the settings you&apos;ve made in the Full-Site Editor. So you have them all in code (Which allows you to push or delete them).&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;![Save Create Block Theme](/images/blog/screenshots/save-create-block-plugin.png)&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;3. Remove the changes&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Ok, now it can be a little bit confusing, but what happens is that now because we have exported the settings to the `theme.json` file, our database is now empty, and WordPress is using the settings from the `theme.json` file.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And that was the goal, clean these settings from the database.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now that we have this settings in our `theme.json` not in the database, but we still don&apos;t want them in the `theme.json` file, so we need to remove them.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And the easiest way is to remove the changes from this current branch.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;git checkout -b remove-full-site-editor&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Here remove-full-site-editor is the name of the branch, you can name it as you want.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Or if you are using a GUI like SourceTree, do right click on the files pending to being commmited and remove them.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now you will see how the Full-Site Editor is reset to the settings of the theme, same as the Production site.&lt;/p&gt;</content:encoded></item><item><title>Add New Custom Field and Query by Weekly Views in WordPress</title><link>https://raulcano.dev/posts/wordpress-custom-field-to-query-by-weekly-views/</link><guid isPermaLink="true">https://raulcano.dev/posts/wordpress-custom-field-to-query-by-weekly-views/</guid><description>How can I filter posts by weekly views in WordPress? In this article, we will show you how to add a new custom field to your WordPress posts and query them by the total views of the week.</description><pubDate>Mon, 08 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;WordPress allows you to create new meta_keys for your posts. This is useful when you want to store additional information about your posts.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;By the other hand the [WordPress CRON event](https://developer.wordpress.org/plugins/cron/scheduling-wp-cron-events/) allows you to schedule events to run at specific times. In this case, we will use it to reset the daily views counter every day, store the daily views in a weekly array, and calculate the total weekly views.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;---&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;1. Add a New Custom Field to Store Daily Views&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;We can add a new custom field in different ways. Without code by using the plugin ACF (Advanced Custom Fields) or with code. In this case, we will use code.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;To add a new custom field, WordPress provides the [add_post_meta()](https://developer.wordpress.org/reference/functions/add_post_meta/) and [update_post_meta()](https://developer.wordpress.org/reference/functions/update_post_meta/) functions. It&apos;s not necessary to use the first one because update_post_meta() will add the custom field if it doesn&apos;t exist.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Code for `single.php`&lt;/h3&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&lt;?php while (have_posts()) : the_post(); ?&gt;

  &lt;?php
  // Get the post ID and increment the daily views counter
  $post_id = get_the_ID(); // Get the post ID from the loop 
  $daily_views = get_post_meta($post_id, &apos;daily_views&apos;, true);
  $daily_views = $daily_views ? $daily_views + 1 : 1;

  update_post_meta($post_id, &apos;daily_views&apos;, $daily_views);
  ?&gt;

  ...Your post content

&lt;?php endwhile; ?&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;By doing so, we can see in the database that the custom field `daily_views` has been added to the post. Inside the postmeta table&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;2. Create CRON event to reset the daily views counter every day&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;To reset the daily views counter every day, we can use the WordPress CRON event. We will create a new function in `functions.php` to reset the daily views counter for all posts.&lt;/p&gt;&lt;h3 class=&quot;zenex-cms__header zenex-cms__h3&quot;&gt;Code for `functions.php`&lt;/h3&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;function reset_daily_views()
{
	$args = array(
		&apos;post_type&apos;      =&gt; &apos;post&apos;,
		&apos;posts_per_page&apos; =&gt; -1,
		&apos;post_status&apos;    =&gt; &apos;publish&apos;,
	);

	$posts = new WP_Query($args);

	if ($posts-&gt;have_posts()) {
		while ($posts-&gt;have_posts()) {
			$posts-&gt;the_post();
			delete_post_meta(get_the_ID(), &apos;daily_views&apos;); // Delete the daily views counter
		}
	}
	wp_reset_postdata();
}

if (!wp_next_scheduled(&apos;reset_daily_views_hook&apos;)) {
	wp_schedule_event(time(), &apos;daily&apos;, &apos;reset_daily_views_hook&apos;);
}

add_action(&apos;reset_daily_views_hook&apos;, &apos;reset_daily_views&apos;);&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;3. Add a New Custom Field to Store Weekly Views With a CRON Event&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;We will create a new function in `functions.php` to store the daily views in a weekly array. This function will be executed every day to store the daily views in the `weekly_views` custom field.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;function add_day_to_week()
{
	$args = array(
		&apos;post_type&apos;      =&gt; &apos;post&apos;,
		&apos;posts_per_page&apos; =&gt; -1,
		&apos;post_status&apos;    =&gt; &apos;publish&apos;,
	);

	$posts = new WP_Query($args);

	if ($posts-&gt;have_posts()) {
		while ($posts-&gt;have_posts()) {
			$posts-&gt;the_post();

			$daily_views = get_post_meta(get_the_ID(), &apos;daily_views&apos;, true);  // Comes from single.php
			$weekly_views = get_post_meta(get_the_ID(), &apos;weekly_views&apos;, true);

			if (!is_array($weekly_views)) {
				$weekly_views = array();
			}

			if (count($weekly_views) &gt;= 7) {
				array_shift($weekly_views);
			}

			$weekly_views[] = $daily_views;

			update_post_meta(get_the_ID(), &apos;weekly_views&apos;, $weekly_views);
		}
	}
	wp_reset_postdata();
}

if (!wp_next_scheduled(&apos;add_day_to_week_hook&apos;)) {
	wp_schedule_event(time(), &apos;daily&apos;, &apos;add_day_to_week_hook&apos;);
}

add_action(&apos;add_day_to_week_hook&apos;, &apos;add_day_to_week&apos;);&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;4. Add a New Custom Field to Store The Total Views During The Week&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;This is a simple sum of the `weekly_views` array. We will create a new function in `functions.php` to store the total weekly views for all posts.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;function total_weekly_views()
{
	$args = array(
		&apos;post_type&apos;      =&gt; &apos;post&apos;,
		&apos;posts_per_page&apos; =&gt; -1,
		&apos;post_status&apos;    =&gt; &apos;publish&apos;,
	);

	$posts = new WP_Query($args);

	if ($posts-&gt;have_posts()) {
		while ($posts-&gt;have_posts()) {
			$posts-&gt;the_post();

			$weekly_views = get_post_meta(get_the_ID(), &apos;weekly_views&apos;, true);

			if (!is_array($weekly_views)) {
				$weekly_views = array();
			}

			$total_weekly_views = array_sum($weekly_views);

			update_post_meta(get_the_ID(), &apos;total_weekly_views&apos;, $total_weekly_views);
		}
	}
	wp_reset_postdata();
}

if (!wp_next_scheduled(&apos;total_weekly_views_hook&apos;)) {
	wp_schedule_event(time(), &apos;daily&apos;, &apos;total_weekly_views_hook&apos;);
}

add_action(&apos;total_weekly_views_hook&apos;, &apos;total_weekly_views&apos;);&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;5. Query Posts by Weekly Views&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Now that we have the `total_weekly_views` custom field, we can query the posts by weekly views. We will create a new file called `most-viewed.php` to query the posts by weekly views.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&lt;?php
$args = array(
  &apos;post_type&apos;      =&gt; &apos;post&apos;,
  &apos;posts_per_page&apos; =&gt; 5,
  &apos;meta_key&apos;       =&gt; &apos;total_weekly_views&apos;,
  &apos;orderby&apos;        =&gt; &apos;meta_value_num&apos;,
  &apos;order&apos;          =&gt; &apos;DESC&apos;,
);

$query = new WP_Query($args);
?&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;This code will return the `$query` we can use to loop through the posts.&lt;/p&gt;&lt;pre class=&quot;zenex-cms__code-block&quot;&gt;&lt;code class=&quot;zenex-cms__code&quot;&gt;&lt;?php require_once(&apos;most-viewed.php&apos;); ?&gt;
// This returns the $query we can use to loop through the posts
...Filter the loop&lt;/code&gt;&lt;/pre&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;How To Test The CRON Events&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;To test the CRON events you can use the [WP Crontrol](https://wordpress.org/plugins/wp-crontrol/) plugin. This plugin allows you to view and control what&apos;s happening in the WP-Cron system.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Then you can simulate the CRON events by clicking on the &quot;Run Now&quot; button.&lt;/p&gt;&lt;h2 class=&quot;zenex-cms__header zenex-cms__h2&quot;&gt;Conclusion&lt;/h2&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;There are of course many ways to achieve this. This is just one of them. You can use this as a base and improve it according to your needs.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Hope this helps you to filter posts by weekly views in WordPress without external plugins.&lt;/p&gt;</content:encoded></item><item><title>From Factory Worker to Developer: The Trigger</title><link>https://raulcano.dev/posts/from-factory-worker-to-developer/</link><guid isPermaLink="true">https://raulcano.dev/posts/from-factory-worker-to-developer/</guid><description>Sometimes, the worst moments can be the start of the best chapters of your life. Embrace change and be grateful for every challenge.</description><pubDate>Sun, 07 Jul 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Usually, we complain when bad things happen to us. But, those moments can be the best fuel to change, grow, and improve. It can be hard to realize it at the moment, but if you think about it, every time you&apos;ve had a problem, you&apos;ve learned something new, you&apos;ve grown, and you&apos;ve gotten better. So instead of complaining, be grateful for the bad things that happen to you.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;---&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I had a friend in the town where I lived in Spain. Let’s call him Carlos. Carlos had been working in a factory for five years, always trying “side projects” while working.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Most of these “side projects,” if not all, failed. Still, when we met for a drink, he was always talking about his next idea.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;What seemed incredible was his routine. Carlos worked the night shift in that factory, where they cut fabric for sofas on demand. It wasn’t a hard job, but it was definitely monotonous.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;When he started in 2016, he was 19 years old and promised himself he wouldn’t be in the factory by the time he was 30. Something that seemed impossible in that town without any studies.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;I think that all the big decisions we make in our lives come with a trigger. No matter how much Carlos wanted to leave the factory before 30, no matter how many side projects he had during the day after working at night, nothing changed until 2021. That year, he didn’t get fired, but his girlfriend left him.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;That day, I remember he called me on the phone. I had never seen him like that: completely lost, without goals, and feeling that nothing made him happy in that town anymore.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;That girl was everything to him at that moment. His last project had failed almost at the same time she left him.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Carlos and I always fantasized about living outside that town. But as I said, big decisions come with a trigger. People tend to talk a lot and do little, until something pushes them to act.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In Carlos’s case, it was hitting rock bottom and feeling he had nothing to lose.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;The trigger was the breakup with his girlfriend and the failure of his project, but the change was moving to Portugal. According to him, what more could he lose? What could go worse? What could be harder than what he was living at that moment? Probably, nothing.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;He went to Lisbon, where he found a job in a call center. And if many people ask, he chose Portugal as he could have chosen another place, he just wanted to leave that town.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It wasn’t his dream job, but it allowed him to live in a city he loved and gave him time to continue with his side projects.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In this case, it was programming, something he always liked, but never saw himself capable of learning.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;It was time to change. It was no longer okay to stay in the comfort zone, no longer okay to lie in bed, or party until the early hours. It was time to get serious.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;From 2022 to 2024, Carlos dedicated himself to learning programming, working on personal projects, networking, taking online courses, reading books, doing everything he could to learn and improve.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;In 2024, Carlos is working as a web developer in Lisbon. He achieved what he set out to do in 2016: not being in the factory at 30.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;All thanks to a trigger, or as we say in my country: “a shitty situation.”&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And well, as you might have guessed, Carlos is me, and this is my little story.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;Nowadays, what felt like the worst time of my life back then, is something I’m really grateful for.&lt;/p&gt;&lt;p class=&quot;zenex-cms__paragraph&quot;&gt;And about Portugal, I had no idea how much this country would mean to me. I just want to say thanks to this amazing country and its people.&lt;/p&gt;</content:encoded></item></channel></rss>