<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: mike</title>
    <description>The latest articles on DEV Community by mike (@mmmagicmike).</description>
    <link>https://dev.to/mmmagicmike</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F294710%2F68f8c4db-b8b4-4404-aba9-41ff46ebd0cc.jpeg</url>
      <title>DEV Community: mike</title>
      <link>https://dev.to/mmmagicmike</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mmmagicmike"/>
    <language>en</language>
    <item>
      <title>Building a Wedding Website with Next.js, Supabase, and Tailwind CSS</title>
      <dc:creator>mike</dc:creator>
      <pubDate>Mon, 30 Dec 2024 10:58:56 +0000</pubDate>
      <link>https://dev.to/mmmagicmike/building-a-wedding-website-with-nextjs-supabase-and-tailwind-css-2k8o</link>
      <guid>https://dev.to/mmmagicmike/building-a-wedding-website-with-nextjs-supabase-and-tailwind-css-2k8o</guid>
      <description>&lt;h3&gt;
  
  
  &lt;strong&gt;Introduction&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In this blog post, I'll share the journey of building a wedding website that includes an RSVP form for our guests. The main goal was to create a straightforward but functional website that allows guests to submit their RSVPs, provide any relevant notes, and request printed invitations. The tech stack consists of &lt;strong&gt;Next.js&lt;/strong&gt;, &lt;strong&gt;Supabase&lt;/strong&gt;, and &lt;strong&gt;Tailwind CSS&lt;/strong&gt;, creating a fast, responsive, and scalable web app.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Tech Stack&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js&lt;/strong&gt;: A React-based framework for server-side rendering and routing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase&lt;/strong&gt;: For backend services like authentication, database management, and hosting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS&lt;/strong&gt;: A utility-first CSS framework that provides flexibility while keeping the UI clean and customizable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cypress&lt;/strong&gt;: Used for testing the form and ensuring everything works smoothly across all submissions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Phase 1: Setting Up the RSVP Form&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The main functionality on the wedding website is the &lt;strong&gt;RSVP form&lt;/strong&gt;. The form collects guest information such as name, mobile number, email address, and RSVP status (attending or not). Additionally, guests can choose to request a printed invitation, available only to residents in the Philippines.&lt;/p&gt;

&lt;p&gt;The form includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Basic fields&lt;/strong&gt;: Name, mobile number, email, RSVP status, and notes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address fields&lt;/strong&gt;: Guests can enter their address if they opt for a printed invitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt;: Using &lt;strong&gt;React Hook Form&lt;/strong&gt; for form handling and validation, we ensure:

&lt;ul&gt;
&lt;li&gt;Mobile numbers are validated based on the guest’s residency (Philippine vs. international).&lt;/li&gt;
&lt;li&gt;Email addresses are validated if provided.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Confirmation Message&lt;/strong&gt;: After submitting the form, guests are shown a success message indicating whether their RSVP was recorded or updated.&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Here’s a sample of the form structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mb-4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="na"&gt;htmlFor&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"email"&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"block text-gray-700"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Email (Optional)&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;label&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
    &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;\s]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[^&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;\s]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.[^&lt;/span&gt;&lt;span class="sr"&gt;@&lt;/span&gt;&lt;span class="se"&gt;\s]&lt;/span&gt;&lt;span class="sr"&gt;+$/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email address&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"w-full px-4 py-2 border rounded focus:outline-none focus:ring text-black"&lt;/span&gt;
  &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-red-500 text-xs"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Printed Invitations&lt;/strong&gt;: Guests can request a printed invitation. A confirmation message will show that printed invitations are optional and available only for Philippine residents. All guests who provide an email address will receive a digital invitation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile Number Validation&lt;/strong&gt;: For Philippine residents, we validate mobile numbers in both short and long formats, while also allowing international numbers.&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Phase 2: Integration with Supabase&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For handling form submissions, we integrated &lt;strong&gt;Supabase&lt;/strong&gt; to store RSVP data. When guests submit their information, the data is saved in the &lt;code&gt;rsvps&lt;/code&gt; table within Supabase. The process includes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Checking for Existing RSVP&lt;/strong&gt;: &lt;br&gt;
We check if a submission with the same mobile number already exists. If it does, we update the entry. If not, we insert a new RSVP record.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Database Structure&lt;/strong&gt;:&lt;br&gt;
The &lt;code&gt;rsvps&lt;/code&gt; table contains fields like &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;mobile&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, &lt;code&gt;status&lt;/code&gt;, and &lt;code&gt;notes&lt;/code&gt;. We also use an auto-incrementing &lt;code&gt;id&lt;/code&gt; for entries.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Reset ID counter and truncate rsvps table&lt;/span&gt;
&lt;span class="k"&gt;TRUNCATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;rsvps&lt;/span&gt; &lt;span class="k"&gt;RESTART&lt;/span&gt; &lt;span class="k"&gt;IDENTITY&lt;/span&gt; &lt;span class="k"&gt;CASCADE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command truncates the &lt;code&gt;rsvps&lt;/code&gt; table and resets the ID counter to 1, which is useful for starting fresh with test data or after a significant update.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Supabase Policies&lt;/strong&gt;: 
To maintain data integrity and security, we implemented &lt;strong&gt;Row-Level Security (RLS)&lt;/strong&gt; policies to control who can view, insert, or modify data in the &lt;code&gt;rsvps&lt;/code&gt; table.&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Phase 3: Testing with Cypress&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To ensure the form works correctly, we used &lt;strong&gt;Cypress&lt;/strong&gt; for end-to-end testing. We tested several important scenarios, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Form Submission&lt;/strong&gt;: Ensuring the correct confirmation message is shown after a successful submission (either new or update).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Field Validation&lt;/strong&gt;: Verifying that the form shows error messages when invalid data is entered.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Handling Duplicate Submissions&lt;/strong&gt;: Confirming that if a guest submits the same mobile number again, the system updates the existing RSVP, rather than creating a new one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is an example of a Cypress test for new submissions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submits the form successfully for a new submission&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;visit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Submit the form with unique data&lt;/span&gt;
  &lt;span class="nf"&gt;fillForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Jade&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+639123456783&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;michael@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;attending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No dietary restrictions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;address_line1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123 Main Street&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;barangay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sta Ana&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Manila&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;province&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Metro Manila&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;postal_code&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Thank you for RSVP-ing!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;By combining &lt;strong&gt;Next.js&lt;/strong&gt;, &lt;strong&gt;Supabase&lt;/strong&gt;, &lt;strong&gt;Tailwind CSS&lt;/strong&gt;, and &lt;strong&gt;Cypress&lt;/strong&gt;, we were able to build a robust and user-friendly wedding RSVP website. This solution allows guests to RSVP, submit their information, and handle updates as needed, all while ensuring data is stored securely and correctly. Additionally, Cypress testing ensures the website functions as expected and provides a seamless user experience.&lt;/p&gt;

&lt;p&gt;I hope this guide is helpful to others looking to build their own wedding websites or similar projects. Stay tuned for future improvements, including styling updates and additional features!&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Next Steps:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Styling&lt;/strong&gt;: Customize the website with more personal designs, icons, and theme-specific colors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Host the website on Vercel or any preferred platform.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feel free to reach out if you have any questions or need further help on your project!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>wedding</category>
      <category>forms</category>
      <category>cypress</category>
    </item>
    <item>
      <title>Untangling Wordpress Spaghetti: a tale about technical debt</title>
      <dc:creator>mike</dc:creator>
      <pubDate>Wed, 28 Jun 2023 12:08:59 +0000</pubDate>
      <link>https://dev.to/mmmagicmike/untangling-wordpress-spaghetti-a-tale-about-technical-debt-4ohn</link>
      <guid>https://dev.to/mmmagicmike/untangling-wordpress-spaghetti-a-tale-about-technical-debt-4ohn</guid>
      <description>&lt;p&gt;If I had a dollar for every Wordpress codebase I touch that’s bogged down with bad coding practices, I'd be a millionaire by now. This isn't surprising in this gig - Wordpress has a pretty bad rep for having crappy codebases, which is why it carries the stigma of poor developer experience.&lt;/p&gt;

&lt;p&gt;This reputation isn't exactly the fault of Automattic, the creators of Wordpress. Wordpress is actually a pretty powerful CMS used by a lot of websites - one which powers 65.2% of all websites in the internet that uses content management systems. But why does Wordpress get this type of hate from the tech community?&lt;/p&gt;

&lt;p&gt;The reason is the low barrier of entry in using the framework. Wordpress is one of the earliest CMSes to have gained adoption from the masses, which not only explains its market share but also why bad Wordpress practices are so common.&lt;/p&gt;

&lt;p&gt;One of my recent tasks as a Wordpress developer is to solely handle the migration of a large events website from BuddyBoss into Bootstrap. For the non-technical: BuddyBoss is a course &amp;amp; community-focused Wordpress theme, while Bootstrap is the most popular HTML, CSS, and JS library. It's a task that I've put off for some time because of the amount of technical debt in the said website. It has been passed over from the original revamp proposal to three different developers/agencies, and me as a sole developer being the fourth entity in this human (web developer) centipede.&lt;/p&gt;

&lt;p&gt;When I first saw the codebase of this website, it's like tracing history through code - first, I saw the poor programming decisions made by the first programmer (which was outsourced to a digital agency). They revamped the website during the time when Wordpress websites were transitioning into Gutenberg. The developers used native Wordpress blocks to replicate the old design, but they did not use Gutenberg properly and resorted to using class-based CSS to implement the styles - which is basically how you get Gutenberg salmonella… because you're eating it raw. &lt;/p&gt;

&lt;p&gt;In the block-based style of Gutenberg editor, the designs should not rely on hardcoded CSS classes, but in using the correct blocks which would make editing easy for the Wordpress end-user. However, because of how developer #1 implemented it, the editors then had to copy each block, with the design component relying into which CSS class(es) are assigned into the block that they copied. Gutenberg was supposed to be Auttomatic's ultimate solution in the longstanding battle of Wordpress visual editors - but this approach butchers that use case.  Unfortunately, this is the path that they took (and in describing their process I am proud to coin the term "Gutenberg salmonella").&lt;/p&gt;

&lt;p&gt;After the agency was finished with the unfortunate revamp, the website was handed over to an intermediate Wordpress developer. Or rather, a developer who heavily relies on plugins but is not that good on customizing them if needed. Don't get me wrong, this approach is perfectly acceptable for the usual Wordpress brochure sites... but not for a website that creates multiple event pages on the daily, and used by dozens of editors from different teams around the world. Because of the need to improve editor capabilities across the site, developer #2 installed several different Gutenberg block editor plugins that would cover every use case possible - but also inevitably heavily overlaps with one another. What happened afterwards is a perfect example of why it isn't good to offer too many choices: with all the block choices they have, the editors went crazy and each used different blocks based on preference - which resulted to a lot of design inconsistencies across the website.&lt;/p&gt;

&lt;p&gt;Developer #2 somehow made it possible for editors to insert text/tabs/images in the pre-defined way these plugins offer, but when more advanced features are needed, they had to hand over the website to more capable hands. Enter developer #3.. a seasoned PHP developer with proven experience under their belt. Were they able to deliver the advanced features that were needed? Yes. But PHP best practices do not necessarily equate to Wordpress best practices (unless you're using an object-oriented Wordpress theme like Sage). Developer #3 introduced object-oriented programming to the site's current implementation of BuddyBoss, which added a working but slightly confusing (almost unnecessary) complexity to the codebase. They were successful in adding advanced features to the site, but were apathetic to the worsening situation of the technical debt that the everyday user (editors) of the website suffers from.&lt;/p&gt;

&lt;p&gt;And now, myself, the one who is destined to finish (and has recently put an end) to this train wreck of bad Wordpress design decisions...&lt;/p&gt;

&lt;p&gt;This post has reached almost 800 words - I'll continue the planning and execution part on another post.&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>bootstrap</category>
      <category>buddyboss</category>
      <category>performance</category>
    </item>
    <item>
      <title>Top 5 Wordpress tips for a more efficient Gutenberg workflow</title>
      <dc:creator>mike</dc:creator>
      <pubDate>Mon, 05 Apr 2021 12:15:28 +0000</pubDate>
      <link>https://dev.to/mmmagicmike/top-5-wordpress-tips-for-a-more-efficient-gutenberg-workflow-5bh2</link>
      <guid>https://dev.to/mmmagicmike/top-5-wordpress-tips-for-a-more-efficient-gutenberg-workflow-5bh2</guid>
      <description>&lt;p&gt;Wordpress came out with Gutenberg for awhile now, but a lot of people hasn't made the switch yet or are still transitioning from their old page builder mindset. I listed out five tips that would help anyone improve their Gutenberg workflow, and build a site faster with the already fast Gutenberg.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Memorize keyboard shortcuts
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Duplicate block&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When building out pages it's more likely that you're duplicating certain blocks multiple times in order to convey information in your content - save time clicking and memorize this keyboard shortcut to improve your workflow. &lt;/p&gt;

&lt;p&gt;(&lt;code&gt;Ctrl + Shift + D&lt;/code&gt; on Windows, &lt;code&gt;Cmd + Shift + D&lt;/code&gt; on macOS)&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remove block&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;It's best to use the keyboard shortcut in order to retain your level in the Gutenberg tree when removing multiple blocks. &lt;/p&gt;

&lt;p&gt;(&lt;code&gt;Alt + Shift + Z&lt;/code&gt; on Windows, &lt;code&gt;Control + Option + Z&lt;/code&gt; on macOS)&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Utilize Reusable Blocks
&lt;/h2&gt;

&lt;p&gt;Gutenberg comes with the concept of reusable blocks - do you have a block that is re-used the same way on several pages on your site? It would be best to save this as a reusable block, that way it's easy to reuse this block across the site.&lt;/p&gt;

&lt;p&gt;Take note that for one to be an effective reusable block, the block must have the same content throughout the whole site. A good example of an effective reusable block is a row containing a newsletter opt-in form that you can use multiple times across the site - and usually the content of such element doesn't change per page. &lt;/p&gt;

&lt;p&gt;If the block changes per instance, it might be better to...&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Utilize Block Patterns
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://developer.wordpress.org/block-editor/reference-guides/block-api/block-patterns/"&gt;Block patterns&lt;/a&gt; serve the exact purpose you think it would - it is a predefined block layout ready to be inserted and modified.&lt;/p&gt;

&lt;p&gt;Instead of writing code to create block patterns the native way, there currently exists a plugin that adds &lt;code&gt;Block Patterns&lt;/code&gt; to the Wordpress admin menu. View &lt;a href="https://wordpress.org/plugins/block-pattern-builder/"&gt;Block Pattern Builder&lt;/a&gt; on the Wordpress plugin repo.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Create blocks easier through ACF Blocks
&lt;/h2&gt;

&lt;p&gt;Similar to block patterns where the native way to create them is to write code, there is a solution that lets you create Gutenberg blocks without heavy Javascript knowledge, one that mainly uses PHP - and this is &lt;a href="https://www.advancedcustomfields.com/resources/blocks/"&gt;ACF Blocks&lt;/a&gt;. It is a fairly new feature of the plugin Advanced Custom Fields for the Gutenberg editor, and has been an amazing solution to create custom blocks for site builds.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Use the &lt;code&gt;Group&lt;/code&gt; block as a row
&lt;/h2&gt;

&lt;p&gt;A lot of people are underwhelmed by Gutenberg because it looks barebones compared to existing Wordpress page builder solutions - but I believe this is an advantage that focuses on just having the right elements or blocks, and minimizing bloat.&lt;/p&gt;

&lt;p&gt;One big feature that was missing for me at first was the &lt;code&gt;Row&lt;/code&gt; element/block - contrary to a WPBakery, Divi, etc. build where a row is a must when creating layouts - hell, even Bootstrap requires using a &lt;code&gt;&amp;lt;div class="row"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; to use its grid system.&lt;/p&gt;

&lt;p&gt;I found a workaround for this - I now use the &lt;code&gt;Group&lt;/code&gt; core block as my row element in Gutenberg. Basically, all elements that would semantically be in a row, I would wrap in a &lt;code&gt;Group&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;The main big benefit is being able to control all outer rows via CSS, using the selector &lt;code&gt;.entry-content &amp;gt; .wp-block-group&lt;/code&gt;. This is especially helpful when you need to adjust the spacing universally for all rows.&lt;/p&gt;

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

&lt;p&gt;Gutenberg maybe confusing at first but with these tips, it helps get Gutenberg closer to the existing page builder solutions. Modern Wordpress is going to this direction, and adopting Gutenberg to your workflow will help you improve as a Wordpress developer. Hope these tips help, and please share your tips in the comment section below!&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>gutenberg</category>
    </item>
    <item>
      <title>Top 5 Must-Have Wordpress Plugins 2021 (Part 1)</title>
      <dc:creator>mike</dc:creator>
      <pubDate>Sun, 04 Apr 2021 07:34:39 +0000</pubDate>
      <link>https://dev.to/mmmagicmike/top-5-must-have-wordpress-plugins-2021-part-1-1fph</link>
      <guid>https://dev.to/mmmagicmike/top-5-must-have-wordpress-plugins-2021-part-1-1fph</guid>
      <description>&lt;p&gt;Did you know that 40% of the web is built on Wordpress? A time and tested CMS, here's a rundown of ten must-have plugins your Wordpress site could use as of 2021:&lt;/p&gt;

&lt;h2&gt;
  
  
  1) &lt;a href="https://www.advancedcustomfields.com/"&gt;Advanced Custom Fields&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NxxR2I_w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/NP4a3EV.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NxxR2I_w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/NP4a3EV.jpg" alt="Photo showing ACF Block and its registration declaration" width="540" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Even before Gutenberg, the Advanced Custom Fields plugin has been a staple to extend the core Wordpress functionality. It introduced ACF Blocks in version 5.8 which has made ACF even more future-proof, now being a part of Wordpress' Gutenberg editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) &lt;a href="https://akismet.com/"&gt;Akismet&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gGU2vnim--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/dTgrf7z.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gGU2vnim--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.imgur.com/dTgrf7z.jpg" alt="Meme saying delete all the spam" width="225" height="225"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Akismet comes with pre-installed with every installation of Wordpress, and that is for a reason. It has a setting where it can get rid of spam comments for you so you don't have to see the spam - it just &lt;em&gt;silently&lt;/em&gt; goes away. Ain't nobody got time for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  3) &lt;a href="https://www.gravityforms.com/"&gt;GravityForms&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I could never build a Wordpress site without GravityForms. It simply is the best forms solution for Wordpress. Whether you need a simple newsletter opt-in form, or if you need a dynamic multi-page form with conditional fields - GravityForms does the job well.&lt;/p&gt;

&lt;h2&gt;
  
  
  4) &lt;a href="https://wordpress.org/plugins/better-search-replace/"&gt;Better Search Replace&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Sometimes you just need to do a quick search and replace on your website to fix a certain typo. Or a raw HTML code that's scattered on multiple pages. Using Better Search Replace lets you do a dry run - that way you can search your database without finalizing the changes. It's the most straightforward search and replace plugin I've used through the years.&lt;/p&gt;

&lt;h2&gt;
  
  
  5) &lt;a href="https://wordpress.org/plugins/duplicate-post/"&gt;Duplicate Post&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;There's a lot of duplicate post plugins on the Wordpress plugin repo, but Duplicate Post has been there for awhile now. It's been so effective at what it does that the team behind Yoast SEO, Yoast, has acquired Duplicate Post last 2020. That's just a testament to how good the plugin is.&lt;/p&gt;

&lt;p&gt;Please let me know if you agree with this list - and feel free to share your top 5 Wordpress plugins as well!&lt;/p&gt;

</description>
      <category>wordpress</category>
      <category>plugins</category>
    </item>
  </channel>
</rss>
