Replace Kitchen Countertop and Topmount Sink with Undermount Sink

The old sink was the top-mount kind. Water kept leaking behind the sink into the base cabinet.

The same quartz countertop was on sale from $500 to $400 (8-foot-long slab).

Found a Mexican guy in the parking lot and got him to transport and install the countertop.

The slab was leaning against the side of the truck and secured using a rope.

To remove the old countertop, I placed a towel on top of it and hit it with a sledgehammer to break it up into small pieces without pieces flying everything.

It actually didn’t take long to remove the old countertop.

I then unscrewed the old plywood and threw it away.

For an undermount sink, you need at least 19/32″ thick plywood. I had Home Depot cut a 4×8′ plywood sheet in have to make two 2×8′ sheets.

I was able to fit both 2×8′ sheets in my car 🙂

I screwed the plywood into the base drawers. There was moisture damage and a hole in the wall which I had to fix.

I patched up the hole and smoothened the wall surface.

That 19/32″ thick plywood should be strong enough for the undermount sink.

I found an 18-gauge undermount sink (30″ x 18″ x 9″ deep) at HD Supply for $175.

The installers cut a hole in the plywood for the sink. They should have used a jigsaw to make the hole.

They cut the countertop outside because it produces a lot of dust.

First, they cut the slab to length. Water was needed to keep the blade from getting too hot and keep dust from going everywhere.

Here, he’s cutting the hole for the sink using an angle grinder. I think he should have used a circular saw to make a straighter cut.

He then polished the edges while his assistant squirted water.

The sink didn’t come with a paper template for cutting a hole in the plywood and countertop. An easy way to mark an outline where to cut the whole is by turning the sink over, sticking your hand into the drain hole, and using a pencil, mark the perimeter.

I had them drill 3 holes: one for the faucet, one for a soap dispenser, and one for the dishwasher.

They put extra strong construction adhesive along the perimeter of the sink hole where the sink lip will sit. They also put it on the plywood in various places to secure the countertop to the plywood.

They then glued the backsplash to the wall and applied silicon to the joint.

When smoothening out silicone or caulk, you should always use a tool like the Husky 3-in-1 caulk tool. The triangular edge makes for a perfect finish.

When installing the p trap, I chose the flexible kind that you can cut to length. It’s much easier than fooling around with metal or PVC drain parts and it never leaks.

And this it how it came out. Not bad at all.

And here’s a close-up of the sink area.

Spirits and The Importance of Regular Spiritual Readings

Contrary to popular belief, we live in a world full of invisible creatures – creatures that some call spirits, jinn, and/or energy. I’ll just call them spirits. Just like humans, some spirits are good and some are bad.

Spirits of ancestors

Some spirits belong to people who have passed away (souls), which is why in many cultures, people give offerings and offer blessings to their ancestors with the hope that their ancestors’ spirits will look out for them.

Other spirits

There are also spirits that aren’t the souls of people who have passed.

Communicating with spirits

Some people are gifted with the ability to see, hear, sense, and/or communicate with spirits. They usually describe spirits as looking ugly. Some spirits are shapeshifters, meaning they can change their appearance to look like anything they want.

Spiritual abusers (witches, etc)

Witches are people who can communicate with spirits to perform witchcraft to hurt others. For example, if someone is jealous of you, they can pay a witch to make you lose your job or never get married. People can also do witchcraft to cheat in life, e.g., to get unfair promotions at work or to make someone want to marry you. Witches send spirits to interfere with people’s lives. Different witches have different backgrounds, religions, and methods. Some methods include animal or human sacrifice, the use of a Ouija board, and sticking needles in a voodoo doll.

Spiritual healers (shamans, exorcists, etc)

Unlike witches, spiritual healers are people who help people who are afflicted by witchcraft and bad spirits. There are many methods, including praying for the victim, having the victim bathe in holy water, lighting certain candles, and having the victim abstain from certain things for a certain period of time. Like witches, spiritual healers have different backgrounds and religions. For example, Christians call their healers “exorcists”. In South America, they are called “shamans”. Some healers follow the religion of Santeria, a mix of the Yoruba and Catholic religions. Others are Hindu, Catholic, and Muslim.

Spiritual readings

Spiritual readings are consultation sessions where people visit a spiritual healer and get information about themselves or someone else. For example, you can ask a spiritual healer if you or someone you know is affected by witchcraft or an evil spirit. The healer will communicate with a spirit to get answers to your questions. Healers have different methods to get information from spirits. Some healers use tarot cards, shells, and candles. Others can just communicate the same way they communicate with people.

Note: not all spiritual healers can provide complete readings. For example, if you are a victim of multiple sources of witchcraft over a long period of time, the original witchcraft needs to be detected and removed in order to remove all subsequent witchcraft. Some healers can only detect and remove witchcraft that was recently done to you. Since this isn’t good enough, it is important to find a healer who can look deep and uncover all witchcraft done to you, especially the original witchcraft, since that would likely trigger subsequent witchcraft being done to you. For this reason, when going for a spiritual reading, it’s helpful to ask the following questions:

  • What are all currently active forms of witchcraft (black magic, curses, etc) affecting me, their source, when they were done, who did them, and how often are they being done?
  • Am I indirectly affected by black magic that targeted someone else, like my parents, relatives, ancestors, past occupants of the home I’m living in, etc?
  • Looking at these photos of my relatives, past and present friends and spouses, and past and present coworkers, did any of them do witchcraft on me?
  • Looking at these photos or addresses of all the places I’ve lived, am I affected by witchcraft from any of these places?

You shouldn’t go to more than 3 spiritual healers to get a reading because the more you go to, the harder it will be to remove any witchcraft.

Different sources of spirit interference

Black magic

Black magic is a type of witchcraft where witches may use an object, like a doll, that represents the victim. They may stick needles in it and bury it somewhere. They may also write someone’s name on a piece of paper, stick a strand of the victim’s hair on it, and bury it where the victim lives. An evil spirit is associated with the object. If the object is destroyed, so is the black magic.

Curse

A curse is when someone wishes evil on someone else. They may perform a ritual or prayer to curse someone. Some healers claim that curses are far worse than black magic because, unlike black magic, where you just need to destroy the object, a curse is difficult to destroy because it moves around in the air.

Evil Eye

The evil eye is when someone intentionally or unintentionally causes misfortune on you because they are envious of you.

Other

There are other ways one can be affected by an evil spirit. For example, if someone does black magic on a pregnant woman, the woman’s child can inadvertently get 50% of the magic. Someone can also be affected simply by moving into a house or apartment that has an evil spirit.

Possession

When someone is possessed, the spirit enters the human’s body and can cause the person to get sick, speak another language, interfere with their mind, and more.

How to get spiritually healed

If you suspect that you or someone you know is affected by bad spirits, you should do the following:

  1. Get a spiritual reading
    You can’t cure what you don’t know. A spiritual reading will tell you what’s going on and whether you are affected by witchcraft, curses, bad spirits, etc. Note that not all spiritual healers will detect all issues affecting you. For that reason, it’s important to ask questions that can help the healer find all issues. For example, if you suspect that you lived in a haunted house, give the healer the address and a photo of the house. If you suspect a coworker did black magic on you, show the healer a lineup of photos and ask if anyone among them did magic to you. By showing a lineup including some trustworthy people, you can also test the healer to see if they are telling the truth. You can also get readings from multiple healers to compare.
  2. Get a spiritual cleansing
    If the reading reveals that you are affected by spirits, then you need to get spiritually cleansed. Costs and methods vary. Whoever you choose to get cleansed, make sure you verify that you have been cleansed. You may get a reading from a different healer to perform the check.
  3. Reverse the evil
    Some people will do witchcraft repeatedly. If they do, then you would have to repeatedly get cleansed. Alternatively, you can reverse the witchcraft such that if someone repeats their witchcraft on you, it will backfire on them. This reversal is not witchcraft but a form of self-defence to deter people from continuing to harm you.
  4. Get protection
    Once you’ve been cleansed, it’s possible to get protection from witchcraft and bad spirits. Some healers may or may not give you an object to wear.

Where to go for spiritual readings and cleansings

There are many spiritual healers with different capabilities, methods, and costs. In the Hispanic community, people often visit a botanica (herbal shop). For example, Botanica Yoruba (Yolanda) in San Francisco, California, charges $85 for a reading, whereas Botanic Mantra in Hayward, California (Carlos) charges $45.

When should you get a spiritual reading?

Spiritual readings can detect more than just black magic. It can detect whether someone is lazy, a liar, sick, or more. Therefore, it can be a useful tool for doing a background check on a prospective employee, tenant, marriage partner, business partner, and more. For example, it is not uncommon for people to do black magic to get ahead in the workplace or to make someone marry them. While these efforts do not directly inflict harm, they still cause harm. For this reason, it is recommended to get a spiritual reading whenever making a big decision. Here are some example spiritual reading checks you can do:

  • Check your fiancé to see if they are affected by witchcraft or have lied to you or is just a bad person
  • Check a prospective job candidate
  • Check a prospective tenant whom you are considering renting to
  • Check the apartment or house you intend to reside in or purchase to ensure it isn’t full of evil spirits
  • Check your parents and siblings; witchcraft targeting your parents can affect you as well
  • Check your supervisor at work
  • Check yourself regularly, like once a year
  • Check your coworkers and friends, as witchcraft is often done by people close to you

Candles

Some spiritual healers use candles to do a cleansing. They may also sell you candles. A ritual (blessing) needs to be done on these candles in order for them to be effective. According to one reputable source, candles that are covered on top have been processed. Candles that are uncovered have not been processed and will have no effect.

Black Candle Soot

After burning a candle, there should be black soot on the glass. This is a sign that the negative energy has been released and the cleansing process is working.

Set-It-and-Forget-It Cheeseburger Recipe

If you’re making a burger and your meat is not frozen, then you can stick a thermometer in your patty and let the thermometer beep when the meat is at your desired temperature. The problem with this is you may have to flip the burger one or more times and, if your patty is thin or not dense, it may be difficult getting the thermometer probe in the center and staying there. If your patty is frozen, like it is at many stores that sell packages of burger patties, then you can’t stick a thermometer in it.

Frozen burger patties may not taste the best, but they are still good. Since they’re frozen, they will last long as well. To simplify the cooking process, I use the T-fal Optigrill. It grills both sides and has a drip tray to catch all fatty juices.

Here’s how to cook a frozen beef patty in the simplest way possible.

  1. Press the power button to turn on the Optigrill
  2. Press the snowflake button because your patties are frozen
  3. Press the burger button since we’re making a burger. The Optigrill will heat up as indicated by the blue light. This takes about 5 minutes.
  1. When the Optigrill beeps, it’s done heating up. Open the lid and place your patties.
  2. The Optigrill will beep and change color every time the meat reaches a doneness level.

When the Optigrill has reached your desired doneness based on the color of the doneness cycle, remove your patties. In my experience, it takes about 7 minutes to get to medium-well.

For the buns, Artesano Bakery Buns are pretty good. Don’t toast these buns. They taste good as is at room temperature.

Almond Mocha Chocolate Latte Recipe

For this recipe, I’m using the PHILIPS 3200 Series Fully Automatic Espresso Machine w/LatteGo.

Ingredients

Instructions

  1. Add almond extract and chocolate sauce to the mug (I use a pipette to transfer the almond extract).
  2. Steam milk to make 1 cup (I put mine in a measuring cup).
  3. Add 1 shot (1 oz) of espresso to your mug.
  4. Pour steamed milk into mug and mix using heat-resistant, scratch-free silicone stirrer.
  5. Enjoy

Fried Rice Made Using Automatic Pot Stirrer

One thing I really dislike when cooking is having to occasionally stir the food. This is the case with fried rice, soups, and stir-fried vegetables. Fortunately, the Koreans feel the same way. A company called LAMPCOOK with the slogan “Innovative Cooking” sells this (overpriced) automatic pot stirrer on Amazon for $155. I normally would spend that much on a pot, but like I said, I really dislike manually stirring food every so often for 10-20 minutes while cooking.

I’ve had the pot for a couple of weeks now and it actually works. But, you can’t put it over heat higher than medium. If you do, you’ll see discoloration at the center.

In this post, I’ll share my recipe for a super simple fried riced cauliflower dish. Riced cauliflower has far fewer calories than rice, and it’s a healthier option. For the flavor, I’ve found either one of the following fried rice packets to be the best.

  • Indofood Racik Bumbu Spesial Nasi Goreng
  • Bamboe Nasi Goreng

Ingredients

  • 1 lb of frozen riced cauliflower (available in packs of 5 at Costco)
  • One of the two spice packets above
  • 1/2 cup of water
  • Oil spray

Instructions

  1. Spray pot with oil
  2. Add water and riced cauliflower
  3. Remove the glass window, turn on the stirrer, and cook on medium
  4. Set a timer for 20 minutes and go do something useful
  5. After 20 minutes, the water should have evaporated. Remove the lid and stirrer arm attachment.
  6. Add the spice mix and stir with a heat-resistant and scratch-resistant silicone spatula.
  7. Optionally, mix in precooked meat, vegetables, eggs, etc.
  8. Transfer to a plate or bowl and enjoy

A Comparison of Chicken Spice Seasoning

There are many spice blends available for chicken. But, which one is the best? I tasted 7 different ones and scored each on a scale of 1 to 10. The winner goes to Target’s Good & Gather Chili Lime seasoning followed closely by Chef Merito Chicken seasoning and McCormick Perfect Pinch Rotisserie seasoning.

Spice SeasoningTaste (1-10)
Good and Gather Chili Lime7
Chef Merito Chicken6.5
McCormick Perfect Pinch Rotisserie6.5
Zatarain’s Creole Seasoning6.3
McCormick Perfect Pinch Cajun6
Old Bay Seasoning5
Lemon Pepper4.5
McCormick Grill Mates Montreal Chicken4
Tajin Clasico3
Chef Merito Chicken Marinade2
Sadaf Garam Masala0

Steak, Egg, and Cheese Burrito Recipe

Ingredients

  • 1x patty of Steak-EZE Thinly Sliced and Shaped Sirloin Steak Strips, Frozen
  • 4 x eggs
  • 1 x 10″ diameter tortillas (the whole wheat carb balance kind has 110 calories, the flour kind has 210 calories)
  • Shredded cheddar cheese
  • Olive oil

Instructions

  1. Warm up the tortilla in a 10″ pan on low heat
  2. Put 2 tbsp of olive oil in a small 8″ pan on medium-high heat
  3. Add the steak patty and cook patty for 2 minutes
  4. Flip patty and cook for another 2 minutes
  5. Using a heat-resistant silicon spatula, break the patty into small strips.
  6. Transfer steak strips to a strainer over a small bowl and press to squeeze juices out. This will limit how much juice will leak through the bottom of the burrito and make a mess.
  7. Flip the tortilla and cook the eggs. I prefer to scramble them.
  8. Turn off the heat to the eggs before they’re done because they will continue to cook on their own
  9. Sprinkle some shredded cheese on the eggs, add the steak, and mix
  10. Transfer the mixture to the tortilla
  11. Let the mixture cool a bit while washing the dishes
  12. Fold the tortilla the way you make a burrito
  13. Enjoy

git cherry-pick Multiple Commits

Cherry-picking individual commits to merge them from one git branch to another is a very common practice. For me, I usually cherry-pick one or more commits from a develop branch to a master / main branch. The problem, however, is when I need to cherry-pick multiple commits made over a long period of time, like one month. Most git clients don’t make it easy to filter commits by keyword, and if they do, then they don’t let you easily select all filtered commits. So, back to the command line it is.

This post will describe one way to easily find all commits matching one or more keywords and extract their commit IDs on one line so you can quickly run the git cherry-pick command.

Step 1: Find and review filtered commits

We usually prefix our commit messages with an identifier so we can filter them amongst many other commits. For example, all commits to related to one project may have a commit message prefix of “LP:8929” where, in this case, “LP” stands for Landing Page. Sometimes, we might accidentally use an equal sign (=) instead of a colon (:). So, we’ll have one or more keywords to search commit messages when we filter all commits.

Furthermore, we usually cherry-pick commits from a develop branch to the master branch while we’re on master. The following command does the following:

CommandDescription
git logget the git log
master..developas we’re on the master branch, get the log from the develop branch
--onelineformat the output in one line (short format)
--grep='LP:8929' --grep='LP=8929filter results to only results containing either ‘LP:8929’ or ‘LP=8929’
-ido a case-insensitive search
git log master..develop --oneline --grep='LP:8929' --grep='LP=8929' -i
48b1cbcef51 LP:8929 - Fixed images path by using imagekit variable
8efa19678b3 LP:8929 - Fixed text alignment
3ab0954c725 LP:8929 - Updated banner and VS page on the landing page
bba58a1c5eb LP:8929 - Updated main heading of features section
fb56da3b134 LP:8929 - Updated content and created carousel as per the requirement
c7c6d50fbdb LP:8929 - Updated styling of the page
bc8a7fc38a1 LP:8929 - Updated icons of the comparison section
9a90ccb91ad LP:8929 - Updated text styling
a3bc0baf65f LP:8929 - Updated headshots and styling of the page
13977d2eb12 LP:8929 - Updated content as per the doc
7e589debba8 LP:8929 - First Pass: Created Landing page of Tenable v Qualys competitive page

Now that we have our list of commits, we need to review them to make sure they are correct. In our case, we primarily want to make sure the keywords are at the beginning of the commit message since that’s our commit message format.

Step 2: Extract commit IDs

If our list of commits is correct, then we need to extract the commit IDs. However, the git cherry-pick command requires the list of commit IDs to be in chronological order. By default, the git log output is in reverse chronological order. Here’s the updated command with some modifications.

CommandDescription
--reverseReverse the git log output to chronological order
awk '{print $1}'Extract only the text output in the first column (commit IDs)
tr '\n' ' 'Replace line breaks with spaces
git log master..develop --reverse --oneline --grep='LP:8929' --grep='LP=8929' -i  | awk '{print $1}' | tr '\n' ' '
48b1cbcef51 8efa19678b3 3ab0954c725 bba58a1c5eb fb56da3b134 c7c6d50fbdb bc8a7fc38a1 9a90ccb91ad a3bc0baf65f 13977d2eb12 7e589debba8

Step 3: Run git cherry-pick command

Now that we have our list of commit IDs in the correct order, we can copy it, type “git cherry-pick” and paste the list to create a command like the following.

git cherry-pick 48b1cbcef51 8efa19678b3 3ab0954c725 bba58a1c5eb fb56da3b134 c7c6d50fbdb bc8a7fc38a1 9a90ccb91ad a3bc0baf65f 13977d2eb12 7e589debba8

Hit enter to run your git cherry-pick command.

Creating a Frontend-only JavaScript App Using Svelte

Svelte is a JavaScript framework similar to React, Vue, etc, but with some fundamental differences that I think make it better. It’s also much more intuitive to understand as the web component structure of the code is dead simple. When building an app using Svelte, you’re encouraged to use Sveltekit, the official Svelte application framework. But, if you just want a simple frontend-only site/app, then you can just use Svelte (without Kit). In doing so, you can then easily take the built CSS and JS files and include them in any existing web page. Then, you just add a simple div

<div id="app"></div>

in your existing HTML file where you want the app go to.

Here’s an example.

Create a Vite Project

Vite is a front-end build tool and dev server. It includes Rollup to bundle and optimize assets. Run npm init vite and follow the prompts. As you can see in the screenshot below, I chose the default project name of “vite-project”.

This will create a folder named after your project and create some files and folders within it.

Then, as the instructions say, run the commands

cd vite-project
npm install
npm run dev

npm install will download the node packages specified in the package.json file into the node_modules folder.

Start Dev Server

npm run dev will launch a dev server. Running the dev script starts a program called Vite. Vite’s job is to take your application’s source files, pass them to other programs (including Svelte, in our case) and convert them into the code that will actually run when you open the application in a browser.

If you go to the local URL http://127.0.0.1:5173/, you will see the starter Svelte app that was created automatically.

The app includes a simple interactive counter. When you click the button, the counter increments.

src Folder

If you look at the src folder, you’ll see a few files:

  • The assets folder contains static assets, like images
  • The lib folder contains Svelte components. In this case, there’s the counter component.
  • app.css is a global CSS file for the entire app
  • App.svelte is your main app code. In this case, it imports the svelte.svg logo and the Counter component.
<script>
  import svelteLogo from './assets/svelte.svg'
  import Counter from './lib/Counter.svelte'
</script>
  • main.js is the main JavaScript file. It loads your app’s CSS (app.css) and your app’s main code (App.svelte). It will also load the app in the HTML element with ID app.
import './app.css'
import App from './App.svelte'

const app = new App({
  target: document.getElementById('app'),
})

export default app

Build the App for Production

When you’re done developing your app (creating components, etc), you can run a build. This will bundle all CSS and JS files into a single CSS and JS file, optimize the bundle (e.g. minify it), and output the production files in the dist (distribution) folder. Run a build with the following command.

npm run build

You’ll see a dist folder created. In this case, with the following files:

If you open index.html, you’ll see it references the two bundled CSS and JS files along with a div element with ID app where the app will be injected.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite + Svelte</title>
    <script type="module" crossorigin src="/assets/index-e83122bb.js"></script>
    <link rel="stylesheet" href="/assets/index-9ea02431.css">
  </head>
  <body>
    <div id="app"></div>
    
  </body>
</html>

Preview Built App

To preview the app from the built files, run

npm run preview

This will run a local server loading the built files.

Different Types of Website Content Management Systems

There are many different types of website content management systems. This post will explain the different types and include some examples.

No-Code CMS

A no-code CMS is one where the entire website is managed by the CMS. For example, with webflow, all changes to your website must be done in the CMS using a WYSIWYG. You can only edit the HTML of the code widget. All other changes must be done using the UI. If you want to edit the source code of the entire site, you must export the entire site. But, you can’t import any changes you made from the export.

webflow

Database-Driven CMS

A database-driven CMS is one that stores some or all data in a database. For example, WordPress is one such CMS. Web pages and blog post content are stored in a database (usually mySQL). Unlike webflow, however, you can edit the source code of the web page templates. WordPress has a built-in versioning system, so you can see a history of changes made to a page.

Headless CMS

A headless CMS is one that stores data remotely. Data is integrated with your website using an API. For example, Contentful is one such CMS. You can create custom content models in Contentful. Your website will need to access the data at a particular URL that returns JSON data. Your website will then need to consume that JSON data to process it to show it on a web page, e.g. by using a template engine. Data in Contentful is likely stored in a database.

Git-Based CMS

A git-based CMS stores data in git version control. Unlike many of the other CMSs, this CMS connects to your git repository as a web developer does. It then shows an interface that allows content editors to make edits to files in the repo. CloudCannon is one such CMS. With CloudCannon, web developers can add the class “editable” to HTML tags with a page’s source code. Then, the content of those tags will be the only elements that content editors can edit.

CloudCannon

FrontMatter CMS

Websites that are built using a static site generator (SSG) often include front matter. Frontmatter can come in different formats. One popular format is YAML. You can have YAML at the beginning of a page’s source code. Or, you can have a separate, standalone .yaml file. YAML contains contain name-value pairs, so they basically represent data. Netlify CMS is one type of CMS that supports editing YAML. It also supports editing pages like blog posts. However, unlike WordPress, where editors can add blocks of content to a page’s body, Netlify CMS requires the blocks of content to be predetermined upfront. So, for a blog post using Netlify CMS, editors can only use one widget to entire the entire body of the page. That widget is a rich text or markdown editor.

Netlify CMS

Structured vs Unstructured Data

The CMSs above can be categorized as CMSs that support structured and unstructured data. CloudCannon supports unstructured data because you can let editors edit specific elements of a complex page by marking those elements as “editable”. YAML and database-backed CMSs support structured data because there is a clear name/value mapping.

My Preference

Since WordPress is the most popular CMS and it allows editors to add blocks of different types of content to the body of a page, I think it’s worth using. However, I don’t like that WordPress keeps data in a database and relies on PHP to build pages before serving them. Also, not all pages need to be edited by non-technical people. In fact, most pages will still be edited by developers who need full access to the source code. To accommodate the needs of both developers and non-developers, I would use GitHub to version all code changes and I would use a static site generator like Eleventy that is integrated with WordPress using the WordPress API. When a WordPress editor saves or publishes a page, WordPress can trigger a save_post() action with a callback function that calls a URL, e.g. a PHP script on Heroku at myapi.com/?postid=123.

function call_commit_script( $post_id ) {
    $remote_url = 'https://www.myapi.com/?postid='.$post_id;
    $access_token = '3&^&2lhl3@#lsjk756'; //some secret password
    $args = array(
    'headers' => array(
       'Authorization' => 'Bearer ' . $access_token,
       ),
     );
    $response = wp_remote_get( $remote_url, $args );
    if ( is_array( $response ) && ! is_wp_error( $response ) ) {
        $headers = $response['headers']; // array of http header lines
        $body    = $response['body']; // use the content
    }
    $post_title = get_the_title( $post_id );
    $post_url = get_permalink( $post_id );
    $subject = 'A post has been updated';
    $message = "A post/page has been updated:\n\n";
    $message .= $post_title . ": " . $post_url\n\n$body;
    // Send email to admin.
    wp_mail( 'webmaster@qualys.com.com', $subject, $message );
}
add_action( 'save_post', 'call_commit_script' );

The PHP script on Heroku could then

  1. verify the Authorization Bearer header contains the predetermined access token value, e.g. 3&^&2lhl3@#lsjk756. If it doesn’t, then the request didn’t come from an authorized origin and should be rejected.
  2. pull any latest changes from GitHub
  3. call the WordPress API to get the page content in JSON format, e.g.
    https://www.mywordpresssite.com/wp-json/wp/v2/pages/123
  4. commit the JSON data to GitHub
  5. use the static site generator to build the page using the JSON data as the data source

To perform git commands in PHP, this PHP library can be used.

Note: the PHP script on Heroku, e.g. https://www.myapi.com/?postid=’.$post_id, must be secured by SSL/TLS to encrypt the URL and headers so that attackers can’t see the authorization header value.

For allowing non-technical people to

  • edit simple YAML files or frontmatter, I’d use Netlify CMS.
  • edit complex, structured data, I’d use Contentful.
  • edit specific, unstructured content, I’d use CloudCannon.