CAll Us: +1 888-999-8231 Submit Ticket

What Is a Platform As a Service (PaaS)?

Once upon a time, software as a service was the only as a service acronym floating around. As the industry flourished though, forks came off of it into relating spaces to create a whole slew of aaS companies in numerous technological categories.

One of those forks is PaaS.

PaaS stands for platform as a service. It’s a service that provides and maintains a platform for developing, testing, and deploying applications for developers. All of the back-end infrastructure is managed by the PaaS, so that the developers can focus on their projects.

PaaS providers are able to reduce the amount of coding you need to do by providing you with middleware to use directly on the platform, with no dependencies on operating system compatibility (aw, yis).

A PaaS makes sense to use when you have multiple developers working on the same project. Like any other team-based SaaS app, PaaS apps allow you to add multiple users in a web-based development environment to co-work remotely on the same project.

Similar to more infrastructure-focused service providers like Hostdedi, PaaS providers include the basic infrastructure required to deploy apps, such as servers, networking, storage, and reference architectures. 

However, PaaS is arguably a more complete solution for app developers, providing an environment which allows you to build, collaborate, test, deploy, and manage your applications, all in one place.

You may not be familiar with the term PaaS, but if you’re a developer, you may already be using one:

  • Beanstalk
  • Heroku
  • Microsoft Azure

Platform as a service companies do one thing: save app developers time and money by bundling and automating a bunch of the things they’re used to doing manually. Then, when you run into problems, there’s a team of experts just behind the curtain to help you out.

PaaS companies are to app developers what Hostdedi is to ecommerce site developers – an all-in-one solution with a team of experts who specialize in your field. You don’t need tier one support at this stage in the game, you need someone who’s at least as informed as you are to help solve these problems.

Check out the PaaS providers above to help build your next application, and when it’s time to launch, talk to Hostdedi about managing your ecommerce site.

Choose From multiple Managed Applications

Source link

What Is PCI Compliance? – Hostdedi Blog

When it comes to processing payments online these days, most people don’t even bat an eye. Shoppers are paying with credit cards, over email, and through Facebook, but for ecommerce sites, payment security risk aversion is integral to how they do business.

Here’s how to make sure that your clients’ sites are staying compliant, and what to do when you’re dealing with an out of date application that’s reached end-of-life.

What does it mean?

First of all, let’s get our heads around what PCI compliance even means.

Originally set by the major credit card companies, the PCI Security Standards Council formed these parameters for payment processing compliance to protect their cardholders from security threats and fraud.

Using a set of qualifications to determine the safety of a point of sale terminal or ecommerce website, these standards are now mandatory best practices between businesses who process card payments and their customers.

The standards for PCI compliance are as follows:

  • Install and maintain a firewall configuration to protect cardholder data
  • Do not use vendor-supplied defaults for system passwords and other security parameters
  • Protect stored cardholder data
  • Encrypt transmission of cardholder data across open, public networks 
  • Use and regularly update anti-virus software or programs
  • Develop and maintain secure systems and applications
  • Restrict access to cardholder data by business need to know
  • Assign a unique ID to each person with computer access
  • Restrict physical access to cardholder data
  • Track and monitor all access to network resources and cardholder data
  • Regularly test security systems and processes
  • Maintain a policy that addresses information security for all personnel

For developers, a separate set of standards has been set by the PCI SSC to ensure websites are processing electronic payments securely:

  1. Do not retain full magnetic stripe, card verification code or value (CAV2, CID, CVC2, CVV2), or PIN block data
  2. Protect stored cardholder data 
  3. Provide secure authentication features 
  4. Log payment application activity
  5. Develop secure payment applications
  6. Protect wireless transmissions
  7. Test payment applications to address vulnerabilities
  8. Facilitate secure network implementation
  9. Cardholder data must never be stored on a server connected to the Internet
  10. Facilitate secure remote access to payment application
  11. Encrypt sensitive traffic over public networks
  12. Encrypt all non-console administrative access
  13. Maintain instructional documentation and training programs for customers, resellers, and integrators
  14. Maintain instructional documentation and training prog

Penalty fines for non compliance can range between $5,000 and $100,000 a month, and inevitably wind up being the merchant’s responsibility. Additionally, merchants can face steeper transaction processing fees, or even the inability to process electronic payments for their customers in the future for non-compliance.

What Developers Need to Know About PCI Compliance

Thankfully, payment applications and payment gateways have taken care of much of the technical side of ensuring that payments are processed securely. As a developer or site builder, your primary responsibility where PCI compliance is concerned is to ensure that your applications meet the PCI SSC’s standards and stay up to date.

PCI compliance standards are determined by the volume of transactions which a merchant processes. The merchant is assigned a compliance level requirement based on the volume of business that he or she does, and the security of their sites may be tested by an approved scanning vendor, or ASV.


Ecommerce sites fall under PCI SAQ 3.1 and have the following standards:

Whether your client requires an ASV really depends on which payment processors and ecommerce applications you’re running their site on. These charts depict the flow of data, so that you can determine whether your client’s site will need an ASV or not.

The burden of site security is ultimately on the site administrator, which may be you. If that’s the case, the strongest prevention for noncompliance is pretty straightforward:

  • Make sure plugins stay up to date
  • Ensure that software updates and security patches get installed
  • Maintain stringent server security standards
  • Make sure ecommerce applications are up to date

What End of Life Means for PCI Compliance

Recently, Magento 1 reached end-of-life, putting thousands of ecommerce sites into a compliance grey area when Adobe stopped issuing official security updates.

While the ecommerce application itself represents only a small part of what PCI compliance truly entails, for merchants still running their ecommerce sites on Magento 1, the important thing to note is there will no longer be security patches and updates issued for the platform. They’re on their own unless they’ve invested in a solution like Hostdedi Safe Harbor

This primarily applies to number seven in the list of PCI compliance measures for developers:

Test payment applications to address vulnerabilities.

With Magento no longer looking after security updates for Magento 1 users, it begs the question: can an ecommerce site be PCI compliant on an ecommerce application that’s reached end of life?

Yes. Hostdedi has done it with Safe Harbor. 

What to Do When a Platform Reaches End of Life

Magento was built on Hostdedi servers. When Magento 1 started approaching end of life, our engineering team jumped to work developing a solution that would allow merchants to decide for themselves when to migrate.

For many Magento 1 store owners, making the move to Magento 2 in the wake of COVID-19 wasn’t financially realistic. Site migrations are expensive and complex, and with so much upheaval and uncertainty, many were understandably scared to make the leap.

So the engineering team at Hostdedi came up with a compromise. Hostdedi Safe Harbor was built to address Magento 1 end-of-life, keeping ecommerce sites and stores owners PCI compliant until at LEAST the end of 2021, so they can migrate on their own time.

With regular security patches made by the team who literally started with Magento, Hostdedi is able to keep Magento 1 sites and stores PCI compliant until they’re ready to make the switch.

End of life doesn’t have to mean the end of PCI compliance.

Get more time, and keep customer data safe with Hostdedi Safe Harbor.

Click here to learn more about Hostdedi Safe Harbor, or open the chat window at the bottom right of your screen to speak to sales.

Source link

How to Duplicate a WordPress Page or Post

WordPress includes a number of features in its core but a number of features you would think would be included fall into the realm of plugins. One such feature is the ability to duplicate an existing page, post, or custom post type on a site using WordPress. 

Luckily, there are a number of solid and easy to use plugins to enable page, post, or any custom post type to be duplicated. One of those plugins is called Yoast Duplicate Post. Using this plugin makes it easy to duplicate a site’s web page or post in WordPress.

How to Install and Activate Yoast Duplicate Post

Go about installing as you would do for any plugin from wp-admin go to:

Plugins > Add New

Then go search for Yoast Duplicate Post and then install and activate the plugin.

How to use Yoast Duplicate Post

Once the Yoast Duplicate Post plugin has been installed and activated it will add a new sub-menu item in settings within wp-admin on the site.

Settings > Duplicate Post

What to Copy


Yoast Duplicate Post plugin supports page, posts, and a number of custom post types. You can also use the plugin to duplicate products and coupons in WooCommerce.

Settings > Duplicate Post > Permissions

When you have the Yoast Duplicate Post setup as you want to cover all of the post types that you might need to duplicate on a site now comes in how you would go about creating a duplicate page or post.

In the page list screen in wp-admin when you mouse over the pages on the site, select the page you want to clone. Once you have cloned the page you will see a new page that is set to be with a post status of draft with the same page title as before.

The clone will show on posts, products as well as any other post types that you might have on the site and those that have been enabled to be supported in the Yoast Duplicate Post plugin.

The Yoast Duplicate Post plugin also includes a number of filters and actions which can be found from this link. Some of the included filters include custom fields that you might not want to be copied when creating a duplicate, if you needed to alter custom fields after a duplicate was created that is also possible.

How to Install and Activate Duplicate Page

There is another plugin option to be able to duplicate a page or post and it is called Duplicate Page.

Go to Plugins > Add New

Then search for duplicate page and you find the plugin to install.

How to use Duplicate Page

The Duplicate Page plugin will add a new sub-menu item into;

Settings > Duplicate Page

You can set which editor the page or post should be created using, the duplicate post status that the new duplicate page or post will be set as, and also you can see what happens after the page or post has been duplicated for the redirect.

In either the post or page list screen, the same will apply for any custom post types that exist on the site such as products if using WooCommerce. Next to the post or page click on the Duplicate This wording and a new duplicate post or page will be created.

Why Would I Want to Duplicate a Page?

Some of the reasons why you might need to duplicate a page, post, or a product would be if you are trying to use a different plugin on a specific page and you want a copy of the page before you update and use a different shortcode on it.

If you are using WooCommerce on the site, you might have a similar product to sell, and the easiest way is to duplicate an existing product. You can use the new duplicated page to update from instead of having to input all of the data from scratch again. If you had a number of changes to make to an existing product but wanted to have a backup copy, then being able to easily clone the product will help.

Source link

The One Thing You Can Do (Without Code) To Speed Up Your Store

You probably already know this, but if your site takes three seconds to load, you’ll likely see more than 50% of your traffic disappear. That’s horrible news if you’re running a blog or business site, but it’s catastrophic if you’re running an online store.

The tips on store performance optimization are endless

Maybe you read about AirBnB, and how they increased their performance by 8% using Google Tag Manager. And that sounds great until you realize that it may be more technical than you’re comfortable with.

Or maybe you’ve read articles that give you a list of things you can do to speed up your store. Below are three articles that help store owners running on Shopify.

You won’t have to spend much time on those sites to discover that they recommend that you use GTmetrix and Google’s PageSpeed Insights tool to get tips to help you find the slow spots on your store.

The problem? 

These tools were created for developers. And if you’re a store owner that isn’t a developer, these approaches won’t help you very much.

We surveyed more than 500 WooCommerce stores

Remember that Google statistic that said pages that take longer than 3 seconds to load get left by 53% of their audience? In a review of more than 500 WooCommerce stores across the globe, we found that the average page performance for more than 450 of them was 3.4 seconds. Ninety percent of the stores were too slow to keep customers browsing – that’s a problem!

While it’s easy to assume that the problem is WooCommerce (or WordPress) that powers the store, we’ve found that there’s a more important culprit – the hosting provider.

The single biggest factor that affects the performance of your store is the hosting configuration that comes from the host you’ve chosen. 

It’s like buying a new car that looks beautiful, comes with a great leather interior, a fantastic stereo and enough space for your entire family and a few friends. If you noticed the performance wasn’t what you wanted, you wouldn’t start by emptying the trunk, would you? No way! You’d check to see if the engine was working.

If your store isn’t performing well, image compression is a great idea but it’s not where you should start. You start with the engine that powers your store – and that’s your hosting environment.

Not all WooCommerce hosting is equal

When you compare hosting companies, there’s a difference between what’s possible and what’s probable. Every host can tell you that they can help your store run well. They’re telling you what’s possible. But that doesn’t mean that you’ll enjoy that performance as a probability.

WooCommerce runs on WordPress and there are a lot of hosting companies that have created solutions focused on WordPress. Right off the bat, those hosts will run a WordPress site faster than hosting companies that don’t specialize in WordPress.

Maybe you’ve heard of one or more of these companies that have created dedicated solutions for WordPress sites. They are, by far, the most famous hosting companies that work with WordPress.

  • Bluehost
  • GoDaddy
  • WP Engine
  • SiteGround

Each of these companies have invested in infrastructure and built custom solutions that help speed up your WordPress websites.

What’s critical to understand is that the very investment that was made to ensure that WordPress sites run fast may not serve your needs when running WooCommerce.

Caching Layers may help WordPress but not WooCommerce

There’s a good chance you’ve already heard different people talk about cache as a magical solution. For the uninitiated, cache is the temporary storage of parts of your website so that customers don’t need to wait for your servers to generate the content again. It’s a shortcut.

If you’ve ever walked thru an airport at lunch time you’ve likely noticed the pizza stands that have personal pizzas pre-made and pre-heated so that you could easily walk up, grab a pizza, pay and walk away. Compare that to the time it would take to order and have a custom pizza made for you, and you’ll easily see why people talk about cache as a great way to deliver high performance to customers.

But these airport pizza places work well precisely because they don’t treat every customer as a unique customer that has unique wants and needs. And the same is true when it comes to the difference between WordPress and WooCommerce.

If you run a WordPress blog or site, the pages you’ve created can be prebuilt and stored, ready for your readers because the pages are the same every time. So having them ready makes things really fast.

But if you do that with your shopping cart, where every customer gets the same cart, with the same items in it, it’s easy to consider that a disaster. Every customer needs to browse the store separately with their own cart. You can’t cache that interaction.

And that’s why we say that the strategies and investments many hosts have made, deep investments, into caching systems don’t actually help WooCommerce stores at all.

Can we talk about another technical aspect of your store?

Imagine you were shopping at a Walmart or Costco, for just a second. Imagine you filled your physical shopping cart and headed to the checkout area. That’s when you notice that there are 20 cash registers but only 2 people checking customers out.

Pretty crazy, right? Well, most hosting companies are just like that. 

Let me explain. Most hosting companies like to talk about storage and memory (hard drive and RAM) as the factors that you need to consider when it comes to the plan you choose. But if we think about your shopping trip, the amount of storage your minivan or truck has is pretty immaterial when you’re in a line of 20 customers waiting to check out. And the credit limit on the card you’re about to use to pay for your purchase isn’t much help either.

What you need is more cashiers. In the hosting world, for stores running on WordPress and WooCommerce – both written in PHP – those are called PHP workers.

When those hosting companies built their platforms, they were counting on their caching systems to ensure that you didn’t need so many PHP workers. The cache would help. And that’s true for WordPress sites and blogs. But it’s not true for WooCommerce stores.

This is why we say not all WooCommerce hosting is the same.

What store owners can do to speed up their WooCommerce store

We promised you that there was something you could do to speed up your WooCommerce without writing any code. By now you likely know what we’re going to tell you.

The simplest thing you can do to get performance gains without doing any development work at all is to change your hosting provider.

But don’t take my word for it. Let’s look at the numbers.

Here’s what we did to compare store performance

The first thing we did was create a sample store. 

  • This store had 2000 products in it
  • We then loaded more than 37,000 orders
  • Then we added more than 9,000 customers

Once we had a sample store, we bought hosting plans at mulitple hosting companies and imported our store onto each of them.

From there we created two sample paths of user interactions – store browsing and store buying. In the first case we navigated between the main catalog and the product pages. In the second, we added items to the cart and checked out.

We did these tests with varying loads – from 50 virtual users to 200 virtual users hitting the store – for fifteen minutes.

Here are the performance results for the same WooCommerce store

HOST Browsing – 50 VU Browsing – 200 VU Buying – 50 VU
BlueHost 10.14 s – 12 min  Too Many Errors 4.59 s – 12 min
GoDaddy** 317 – 429 ms 390 ms – 6.77 s 772 ms – 2.48 s
WP Engine 3.13 – 3.21 s 3.16 – 3.21 s 5.08 – 6.03 s
SiteGround 1.89 – 4.74 s 2.52 s – 2 min, 42 s 2.93 – 58.54 s
Kinsta 1.91 – 2.46 s 1.95 – 2.17 s 1.73 – 1.91 s
Liquid Web 1.65 – 1.99 s 1.67 – 1.76 s 1.65 – 1.88 s

** GoDaddy is one of the hosts that has an aggressive cache in place that makes it great for WordPress sites but completely incompatible for WooCommerce stores. Because it’s impossible to turn off their caching, orders are not able to be processed. The result is a very fast page load that doesn’t allow customers to buy anything.

The comparison isn’t much of a comparison, is it?

There is no question that you could optimize a store to perform better on every one of the hosts we compared. If you were a developer, you could look for tips that help you minify your JavaScript, use tools to compress your images, and more. We strongly suggest getting a development partner to help your store.


The one thing that both Kinsta and Liquid Web have in common is that they’re relatively newcomers to the WordPress and WooCommerce hosting environment. We normally get hesitant about new companies, waiting to see how things pan out. But what these two hosts have demonstrated is that the older paradigm of building cache-heavy solutions for WordPress hosting isn’t a solution for today’s highly interactive sites and stores.

In the case of Liquid Web that provides a dedicated solution for WooCommerce hosting, they go further by automatically optimizing images, adding performance tuning, and database-specific optimizations for WooCommerce stores.

The point we’re making here is that store owners have one move that could change the performance of their stores without any coding. And the result of that change could be a 30-300% different in load times. 

Most importantly, a faster store delivers a better experience for customers, and that’s a difference that leads to greater revenue.

Source link

5 Real Differences Between Cheap Hosting and Good Hosting

Have you ever looked at the price difference between two products and gone, “What the hell?? WHY is that one so much cheaper?”

It’s like buying something on Wish versus at Target – price is everything, but a race to the bottom is not without consequences. You get what you pay for typically, and when it comes to hosting technology, that’s especially true.

With so much technical terminology, it’s hard to really communicate exactly what the difference is between two dollar and 20 dollar hosting. It all sounds pretty much the same, right?

Fast. Secure. Reliable.

We’re normally pretty nice guys around here, but we’re also crazy honest – there’s a reason we don’t feel bad for not being the cheapest, and it’s the same reason that Target doesn’t feel bad for not being more like Wish.

What’s the Difference Between Managed and Unmanaged Hosting?

  • Application updates
  • Plugin updates
  • Malware monitoring

With managed applications from Hostdedi, you’re also getting a support team made of application subject matter experts, who understand coding and these applications enough to help you diagnose problems on both sides of things.

How Much Does Hosting Usually Cost?

Buying hosting is kinda like buying a data plan. You get a connection to a server, you get data limitations and storage space, and some technical infrastructure on the back end to make sure that everything is running smoothly.

On the managed hosting side of things, like what we do here at Hostdedi, you get a lot more than just that connection and storage space. You get a level of administrative service that, though largely automated, keeps your plugins working together nicely and your site up to date (because let’s face it: we all forget).

Hosting plans are structured similarly to data plans in that you get a certain amount of bandwidth and features and functionality at staggered price points.

For a simple website, hosting typically costs between $3 and $45 per month for basic, unmanaged hosting. For managed hosting, the range is more like $7 to $45 per month.

As you’re getting into more complex projects, like ecommerce websites, or sites with a lot of traffic and complex server demands, those plans tend to get more expensive. 

The 5 Skeletons Hiding In Cheap Hosting’s Closet

#1 – Unlimited Bandwidth Isn’t Actually Unlimited

Have you ever increased your data plan for your home internet, only to find that your data overages turned into a slower connection?

It’s not in your head. This is called throttling, and it’s what happens when a user eats up a lot of bandwidth, but can’t be charged any overage fees.

The same thing is true for hosting. Though many cheap hosts claim to offer unlimited bandwidth, the reality is that there’s no such thing. Unless you’re dealing with a host with cloud infrastructure, it’s literally impossible for the bandwidth to be unlimited because you’re dealing with a physical server with physical capacity limitations.

#2 – They Use the Fine Print to Throttle Your Speed

Since unlimited bandwidth isn’t actually a thing, a lot of cheap hosting providers put weird clauses in their terms of service to make it technically legal for them to call their service unlimited, and then still, well, limit it.

For example, Godaddy has an ecommerce plan that offers unlimited bandwidth. The only catch? It’s against their terms of service to upload multimedia content to your website. No product videos for you, buddy.

#3 – Traffic Surges Will Produce 502 Errors

Related to unlimited bandwidth is a physical server’s inability to automatically scale your bandwidth and concurrency needs when you get a surge of traffic.

Long story short, if you have cheap hosting and you plan on killing it this holiday shopping season, you’re more likely to see llost sales due to 502 errors than record-breaking numbers.

#4 – When It Comes to Applications, You’re On Your Own

Cheap hosts typically have a very narrow scope of support. What this means is that when you’re having an issue and using an application, like WordPress or WooCommerce, you’re not likely to get much help out of them.

If it’s not server-side, you’re out of luck. They’re going to send you to the application’s support team, who will in turn, likely send you back and forth with a series of things to try, until you eventually scream in agony and throw your laptop out the nearest window.

Not good.

#5 – Cheap Hosting Usually Comes With a Long Term Commitment

In a lot of cases, cheap hosts know what they’re selling, and they know better than to make it easy for you to just walk away. That’s why in a lot of cases, those $3 hosting providers are going to try to get you to commit to a long term agreement that you’ll have to pay to get out of early.

Look, hosting is like the foundation and walls of your house. If someone asked you where you’d like to save money in building your new home, would you start there?

Of course not. Because literally your entire home is built on that stuff.

Hosting is no different, and scrimping on it to save a few bucks a month is akin to hiring the sketchiest contractor you can find to pour your foundation. It’s not worth the risk, and you don’t have to spend a lot to get great hosting anyway.

Buck up ya cheapskate – you’re not building websites because you have a ton of free time. You’re building them because you want your work out there in the world and you have a vision.

Don’t build your vision on a flimsy hosting foundation – build it with Hostdedi.

Free Trials

Source link

Adding Custom Triggers to AutomateWoo

Email marketing is key to running an effective eCommerce site. While there are many good email marketing platforms out there, many don’t have very deep interactions with WooCommerce. If you start looking at all the plugins available for WooCommerce and their capabilities, there are almost no email marketing platforms that interact with many of the different events you’ll want to use.

This is where AutomateWoo fills a huge gap. AutomateWoo is built specifically for WooCommerce; to automate your customer interactions completely inside your WordPress admin interface. This means that it has fairly deep hooks into WooCommerce that you can leverage. This also means that it’s built using WordPress best practices for plugin development and doesn’t need to interact with a 3rd party server.

Today we’re going to take a look at what AutomateWoo can do for you out of the box. Then I’m going to walk you through the process of creating a custom trigger for those few times that AutomateWoo doesn’t cover one of your use cases.

AutomateWoo Trigger Basics

AutomateWoo works by detecting actions that users take. Once an action is recognized by the plugin, it allows you to trigger events. If that sounds a bit confusing, let’s use AutomateWoo to send a thank you email to a customer once they have spent over $200 in our store.

To start go to AutomateWoo -> Workflows and then click Add Workflow at the top of the page.

Next, create a descriptive title for your Workflow. I titled mine Customer Spend Reaches

Now we need to choose the trigger we want to use. Click on the select box and choose Customer Total Spend Reaches from the list of available triggers and then set the total spend value to $200.

Now we need to choose an action to take when a customer spends more than $200 in our store. Click the blue + Add Action button and choose Send Email as the action we want to take.

As you fill in what you want to say to a customer remember that you can use any of the variables that are listed on the right-hand side of the screen. To use a variable you need to use double curly braces around the variable name. That means to use the customer’s first name (if they have one in your system) you’ll use {{customer.first_name}} in your text where you want that information to show up.

Once you’ve got the email content you want, scroll back to the top of the page and click the blue Save button so that your Workflow is saved and ready to go. If you’re working on a Workflow, you can change the status of it to Disabled and then click Save. Marking a Workflow as Disabled will ensure it doesn’t run while you’re working on it.

Do pay attention to the status of a Workflow. I’ve had workflows running that I didn’t want running, and also thought I had a workflow active that was disabled. Always double-check the status of your workflow once you’ve finished working with it for the day.

One feature of AutomateWoo we haven’t touched on yet is their rules. Rules allow you to filter which type of customer a rule works for. You could use two different rules to reward the repeat customer above based on where they are. Maybe you can mail customers in your country a card and you use a rule to send yourself an email with their address when they reach the threshold. For users outside your country, you could send the email above instead of the card.

Create a Custom AutomateWoo Trigger for WooCommerce Teams

Despite the deep hooks that AutomateWoo has in WooCommerce, it doesn’t cover every case for every plugin. For a client I worked with recently, we wanted to send each new team member an email as they were added to a team inside Teams for WooCommerce Memberships. AutomateWoo doesn’t provide a trigger for this out of the box, but it is possible to add your own custom triggers to AutomateWoo.

To start we need a base plugin, which you can see below.

<script src=””></script>

While it’s possible to have a single plugin file and include all the custom triggers you may want, I don’t like doing that unless I’m 100% sure that I’m only adding a single trigger. If you end up adding more than one or two triggers you end up with a huge plugin file with functions spread all over and it becomes hard to manage which trigger your dealing with at any one time. Instead, I like to keep each trigger in its own file and include them in the main plugin. This makes it easy to pick out which trigger you’re working on.

We will need to include the main trigger registration in the plugin though, so let’s do that and include the file that will contain our trigger. Inside our init function add the trigger filter.

add_filter( 'automatewoo/triggers', array( $this, 'add_to_team_trigger' ), 10, 1 );

That’s a filter hook in WordPress. Filters allow you to change data as it passes through the code. In this case, we’re going to add to an array in the next block of code.

This in turn calls a function called add_to_team_trigger which will register our new trigger for AutomateWoo. Just below our init function add the following code, which should make your base plugin look like this.

public static function add_to_team_trigger( $triggers ){

    require_once( 'trigger-add-to-team.php' );

    $triggers['nexcess_add_to_team'] = 'Nexcess_Add_To_Team_Trigger';

    return $triggers;


Note that just before we adding to the $triggers array, we required a file called trigger-add-to-team.php. Now we need to create that file so that we have a trigger in AutomateWoo. Create a file called trigger-add-to-team.php in your plugin folder and then paste the code below into it.

<script src=""></script>

Now, let’s walk through what the code is doing. Lines 3 – 5 are about security. They stop anyone up to no good from directly accessing the file itself. Next, we define a class called Nexcess_Add_To_Team_Trigger which extends the base functionality of AutomateWoo’s Trigger class. Line 14 defines the data that is passed to our trigger.

In our init function we define two things. First, we define the name of our hook and second, we say what group it should go in. You can use the existing groups in AutomateWoo or you can define a custom group. In this case, we used the Team group because the trigger is related to WooCommerce Teams. Any future team trigger would go in the same group.

If our trigger needed to load any custom UI elements we’d use the load_fields function. We don’t have any (and I’ve never needed any) so we’ll just leave that alone.

The register_hooks function is what catches what’s happening in WooCommerce teams so that we can do something when a new team member is added. If we go to the Team.php file in WooCommerce Memberships for Teams and go to the end of our add_member function we’ll see that once a team member has been added successfully it calls the hook named wc_memberships_for_teams_add_team_member.

Note that wc_memberships_for_teams_add_team_member passes the Member object and not a user_id which is what AutomateWoo expects to get on line 47. That means we need to take the Member object and get the user_id from it on lines 43 and 44 so that we can pass the user_id to AutomateWoo.

wc_memberships_for_teams_add_team_member is an action hook. This allows you to detect when an event happens in WordPress so that you can do something else based on the occurrence of the event. You can read more about WordPress Hooks in the documentation.

By adding to this action hook we run our trigger once a new member has been added to a team.

Next our catch_hooks function is called by the register_hooks function, specifically it’s called here when the wc_memberships_for_teams_add_team_member action is run. This is going to pass the user_id to the rest of AutomateWoo so that we can send a user an email.

The result of all this code is that if we create a new Workflow in AutomateWoo we see that we have a new trigger which lets us run a Workflow when a new user is added to a team. Make sure your custom plugin is activated and then create a new workflow using our new trigger.

That’s it, we now have our custom trigger working for AutomateWoo. You can see the completed plugin here

To add custom triggers for other events on your site you’ll need to look for other action hooks so you can detect different events as they happen. Using pretty much the same code above I could also email a user when they are removed from a team by using the wc_memberships_for_teams_after_remove_team_member hook in the same Teams.php file.

Source link

Magecart Attacks Again: the Latest on CardBleed

Only a couple of weeks after the first vulnerability with an associated CVE was discovered for Magento 1 after its end of life, reports about a large scale Magento 1 hack attempt surfaced. 

While stats are not definitive, as of today, around 3,000 sites were hacked. This attack, usually referred to as MageCart, is the most common type of attack against Magento 1 and it’s typically used to collect user credentials and credit card information from the application inputs and exfiltrate data to remote servers.

After carefully reviewing public reports and our WAF logs, Hostdedi identified the threat and swiftly added a fleet-wide block for /downloader. We also isolated the malicious content added to this prototype.js file and have removed it from every file, leaving the original malicious file as backup (prototype.js.bk) for the client’s reference. 

We already had filters for this, mostly against brute force attacks. But given that Magento discontinued Magento Connect after June 2020, we decided to block access and only re-enable it upon request for certain IPs. 

This is one of the biggest differences between a code based Magento 1 maintenance package versus a hosting-based approach. While almost every project issued notices and recommendations, they all required user intervention. 

Our approach was to deploy a fix to the entire server fleet without any user intervention.

While a few stores were impacted, the immense majority remained safe because of the infrastructure and systems we already had put in place. This foundation, plus our swift action, helped thousands of Hostdedi stores and customers to remain secure.

In addition, we released Nexcess_CSP for our Safe Harbor users. Content Security Policy (CSP) is an added layer of security that helps detect and mitigate certain types of attacks including Cross Site Scripting (XSS) and data injection attacks usually known as MageCart. This module helps any Magento 1 store to set CSP policies, avoid and report XSS attacks and has 2 main objectives:

  • Mitigate cross site scripting: disallowing the communication to certain URLs by specifying the domains that the browser should consider to be safe sources of scripts.
  • Mitigating package sniffing attacks: specifying which protocols are allowed to be used; a server can specify that all content must be loaded using HTTPS.

We did not find any intrusion for stores that had CSP_Nexcess installed and properly configured.  Hostdedi Safe Harbor provides an extra layer of protection against this type of attacks, which are likely to continue.

The best kind of protection against external attacks is a mix of server side protection in the form of a WAF plus modules and patches to keep your store protected.

Keeping your Magento 1 store fully operational means protecting it against known vulnerabilities. If you have yet to invest in Safe Harbor, this hack illustrates the importance of staying secure.

Hostdedi Safe Harbor is a sound foundation to keep your sites and stores protected while you are on M1.

Source link

Passing the Torch – Hostdedi Blog

No matter where you stand politically, you can’t deny that Ruth Bader Ginsberg was a force. I have a special place in my heart for her as we’re both from Brooklyn. Her demeanor, her mannerisms, and her grit take me back to the 1970’s-1980’s New York of my youth. You don’t mess with Native Brooklynites. We don’t all sound like Tony Manero, but our strut is innate.

As working men and women, there are many reasons to be grateful for RBG’s contributions to our society. Her history is now documented everywhere – from no one hiring her after she graduated first in her class from Columbia, to losing her job because she got pregnant. Her personal challenges and beliefs drove her to fight for justice and equal protection under the law for all of us. 

Navigating a Path to Leadership

I have worked in tech for 20+ years and we all know the stories. With the exception of crossing paths with one or two extraordinary female leaders during my career, I’ve seen first-hand the limitations and struggles faced by women, including myself, to navigate a path to leadership. When I landed at Hostdedi, the tides turned. It’s not lost on me that my peers and I are incredibly fortunate to work for a company that hires really smart individuals to do really smart things. Our culture, built on entrepreneurship, supports our strengths, our skill sets, and the ability to learn as you go. 

Our COO is one of those extraordinary women. And we’ve got a plethora of women in leadership roles across the organization – Marketing, Operations, Sales, and Channel. We are surrounded by team members who recognize our achievements, respect our work, and look to us to pave the way as they navigate their own careers. 

We didn’t get here by playing it safe. We all took risks. Got shot down. Were likely bypassed for promotions. Had others steal our ideas and claim them for their own. Maybe we didn’t talk enough. Or maybe we talked too much. Many of us had to figure out how to juggle managing a household and being a parent while still striving for professional success. These challenges are faced across traditional fields for women working outside of the home, but tech offers its own set of obstacles to overcome. Tenacity and confidence are key drivers that ensure you never give up on yourself. Even if others do. 

A North Star for All of Us

RBG’s persistence and attitude towards her professional mission should be a North Star for all of us. A strong sense of self, confidence that doesn’t turn into arrogance, an honest interest in helping others, a passion for learning, and an ability to grow and evolve.These are key attributes for every leader, no matter their gender. 

It is our duty to offer career paths to those that follow us. Opportunities to learn and grow. Mentorship to address issues that may be better than they were yesterday, but still require navigation. To empower our teams, welcome their ideas, be confident enough to recognize better ideas, and allow everyone to pursue greatness. 

Thank you, Ruth. We will take what you’ve given us and pass the torch. 

Source link

Deploy WordPress with Github Actions

A while back I showed you how to deploy your WordPress site with Deploybot. I’ve used this service for years now, but when I started, it was out of my price range, so I used nothing and made many mistakes deploying my sites which cost me many lost hours and some tears.

Today, I’m going to walk you through how to use Github Actions to deploy your site automatically for no cost. The set up is more complex than Deploybot, but it’s going to be free for most projects.

This post has a bunch of working parts so set aside some time, especially if you haven’t worked with Git or SSH keys before. We’re going to cover:

  • Creating a Hosting Account
  • Getting your code into Git
  • Creating special deploy SSH keys for Github to use
  • Configuring the Github Actions YAML file
  • Using Github repository secrets to keep private information safe
  • rsync via ssh

What Are Github Actions?

Github Actions is a feature of Github that allows you to automatically perform tasks based on the state of your code. Today, we’ll look at deployment, but you could also have an action to run your unit tests or notify a Slack chat when someone makes a new PR on your project.

While they may take a bit of time and effort to set up your first time, they return the investment by letting you get back to code instead of worrying about repeating the same work over and over. 

Getting Your Site Set up

The first thing you’ll need is to create a hosting account on Hostdedi, so head over and check out the plans available. The Maker WordPress plan is a good plan if you’re hosting a few sites.

With your site set up, go to the backups and create a backup of the site before you do anything else. Make sure you download this backup as well so you have a copy on your computer…just in case.

Unzip the backup and then copy out the public_html folder to use as our git repository. You can remove the wp-config.php file because we won’t need it today.

Now that we have our copy of the repository downloaded, let’s add it to Github. To start we’ll need to create a new repository in Github. Add your title and whatever description you want, I usually don’t initialize the repository with a README because I’ll provide my own with any project-specific notes and documentation for a client project.

Next, open up Terminal and cd into the downloaded copy of WordPress so you can initialize the repository with git init. The first thing we want to do is add our .gitignore file so that we don’t add any files that may overwrite what Hostdedi needs to run your site. You can use the .gitignore file provided below.

The top eight lines are specific to Hostdedi, so make sure you copy those lines if you have your own preferred ignore configuration.

If you’re not familiar with Git, check out my post on Introduction to Git.












































Now that you have the ignore file ready, use git add and git commit to add the WordPress files to your repository. Then push those files to your Github repository.

Creating a Deploy SSH Key for Github

To deploy our site via Github Actions, we’ll need an SSH key for the action to use. Do not use your regular SSH key.

To generate the SSH keys needed use the command below using your email. When prompted for a passphrase, press enter and leave it blank. When you’re asked for a location, choose a location to store them temporarily. You can find Github’s documentation on SSH keys with extra details here.

ssh-keygen -t rsa -b 4096 -C "[email protected]"

Before we take the next step, make sure your new SSH keys are stored safely. I store them in my 1Password vault alongside the other server credentials. Don’t leave them sitting in some folder on your computer because if someone gets your keys they get access to any server those keys are used on.

Now, open the public key (the one that ends in .pub) and open it in the text editor of your choice. In your Hostdedi account, click on your account name in the top right corner and select SSH Keys.

Next, select Add Key and copy/paste the whole key out into the main text field. Make sure to label your key properly so you can tell what the key is being used for.

Finally, click Add to save the key to your account.

Adding and Configuring Your Github Action

Before we start to build our action, we’ll need some secret information stored in our account. Stuff like our private key for the key pair we just created, the location of our server, and the entry for the known_hosts file.

Start this by choosing Settings from the top right of your repository. Then choose Secrets from the left column. We’re going to add 3 different values.

  1. DEPLOY_SSH_KEY: This is the private key we generated (doesn’t have .pub at the end)
  2. NEXCESS_LOCATION: The location SSH will access on our server plus the file path to your html directory. Making a mistake here could delete your site, but this is why we took a backup.
  3. NEXCESS_HOST: The allowed host file we need from our server

You already have 1 so open your key file and copy it’s entire contents into a secret called DEPLOY_SSH_KEY.

Next, you can get the location of your server from your Hostdedi control panel for your site under the Access menu.

Finally, the easiest way to get the content for NEXCESS_HOST is to ssh into your server from your computer. This should prompt you to accept a new known server. Accept the new server and then you can head to ~/.ssh/known_hosts and get the last line in the file for the secret you need to add to your repository.

Why are we keeping this stuff secret? Each of these pieces of information has some security risk so you don’t want them in your repository. Putting them in a secret variable in Github makes sure you don’t expose information by accident.

We’re ready to head back over to our repository on Github and get our action going. Start by going to the Actions menu at the top of your repository and click on it. While there are lots of prebuilt actions, we’re going to start by creating our own action so select that from the Actions screen.

Doing this will give you a basic workflow file written in YAML. By default, it works only on your master branch, but by changing which branch is in the arguments on lines 9 & 11 you can make it work for a different branch. You may do this if you wanted to deploy from a staging branch to a staging site and from master to the live site.

Starting with the line below, delete the rest of your default workflow file.

# Runs a single command using the runners shell

    - name: Run a one-line script

      run: echo Hello, world

Now we need to get our SSH agent. On the right hand side of the workflow screen search for webfactory/ssh-agent.

Click on this and it will provide you with some commands to copy and paste into the bottom of your file, but we’re going to use our own custom script. Copy the code below and paste it into your workflow file below the actions/[email protected]

   # Setting up SSH

    - name: Setup SSH agent

      uses: webfactory/[email protected]


        ssh-private-key: ${{ secrets.DEPLOY_SSH_KEY }}

    - name: Setup known_hosts

      run: echo '${{ secrets.NEXCESS_HOST }}' >> ~/.ssh/known_hosts

    - name: Sync project files

      run: rsync -uvzr --backup --backup-dir='~/deploy-backup/' --exclude 'wp-config.php' --exclude '.gitignore' --exclude '.git/*' --exclude 'wp-content/uploads/*' --exclude '.htaccess' --exclude 'wp-content/cache/*' --exclude 'wp-content/advanced-cache.php' --exclude 'wp-content/object-cache.php' --exclude 'wp-content/mu-plugins/*' ${GITHUB_WORKSPACE}/ ${{ secrets.NEXCESS_LOCATION }}

You can see the secrets we set up earlier in this file. It starts by pulling in the ssh-agent and adds our private DEPLOY_SSH_KEY to the server it’s getting ready in the background. Next, it adds our server as a known host.

It finishes by syncing the project files over to the live server in a long rsync command. In short, it backs up the remote server into a directory called deploy-backup and then moves any new files in the Github project over to the live server. We excluded all the same location we ignored in our original .gitignore file so that rsync doesn’t touch them by accident.

If you want to read up on each rsync command there, I usually refer to this Ubuntu documentation on rsync

Now all you need to do is make some changes in your repository and then use git to add and commit them to your repository. Push those changes to Github, and the action will automatically backup your files and then push your changes over to your site.

If you’re new to automatic deployments, this does seem like a lot of work. Even my first time using Github Actions to deploy my site I spent a few days working on the script. This doesn’t feel like it saves time until I’m using the same script for weeks with a project deploying regularly.

Automating your deployment, and taking the time to get it right, means you never accidentally overwrite the wrong files, put the wrong files in the wrong directory, or make any other of the many mistakes I’ve made moving files around in the 12 years I’ve been building sites.

A day or two of time spent configuring deployment for your first time is worth saving that pain.

Source link

Introduction to Unit Testing for WordPress

While many of us have heard of unit testing, it’s not a big topic of discussion in the WordPress community. Yes, there are tests for WordPress core. Yes, many of the major plugins like WooCommerce have unit tests, but that doesn’t make it easy to jump on the unit testing train. 

While you can find lots of content about unit testing PHP applications, there aren’t many people talking about unit testing specifically for WordPress. There is precious little written about where to start for developers that are ready to increase their code quality and want to learn how to add tests to their work. Even worse, some of the tools for unit testing in WordPress don’t work as advertised, or are using older versions of PHPUnit. Problems you’ll have to discover on your own as you try to start testing.

That leaves many people who want to get started with testing on a multi-hour journey to get even the basic default tests running for their plugin.

Today we’re going to solve that problem by giving you an up-to-date look at how to start unit testing your WordPress code.

Things to Have Installed

Before we dive into unit testing, I’m going to assume you have Laravel Valet and WP CLI installed. I use these excellent directions from WP Beaches to install Valet, though I use the mysql instructions not the MariaDB ones. 

You can find the instructions to install WP CLI on the WP CLI site.

If you’re on Windows, you may have a bit of extra digging to do so you can run unit tests. The WordPress Handbook has some instructions on the extra steps you’ll need to take.

Install PHPUnit for WordPress on Laravel Valet

Our first step is to install PHPUnit. While PHPUnit is currently on the 9.x branch, WordPress only supports 7.5.x which means we’ll need to install this older version.

Open up the terminal and use these commands.


chmod +x phpunit-7.5.9.phar`

sudo mv phpunit-7.5.9.phar /usr/local/bin/phpunit

phpunit --version

The command above, download PHPUnit. Then we make the file executable so it can be run. Next, we use the sudo command to move the file to the proper location on our computer. Finally, we check for the version number, which should return 7.5.9 when we run the final command.

Now we’re ready to set up our plugin with WP CLI and take a look at our first tests.

Setting Up Our Plugin

We can make starting a plugin, and getting our unit test scaffold, easy with the WP CLI scaffold command. This command will create a plugin for us, and add all the files we need to have a foundation for our tests.

In the terminal, make sure you’re in the proper WordPress directory you want to use and then type wp scaffold nexcess-unit-tests. That should give you a folder structure that looks like this.

– bin


– tests

    – bootstrap.php

    – test-sample.php

– .distignore

– .editorconfig

– .phpcs.xml.dist

– .travis.yml

– Gruntfile.js

– nexcess-unit-tests.php

– package.json

– phpunit.xml.dist

– readme.txt

If you want to build out the basics of a plugin but not include tests then you’d use the –skip-tests flag, which will skip the generation of test files. You can see all the options available for this command in the WP CLI documentation.

Depending on how your code editor and file system are set, you may not see the files that begin with a . because they’re considered hidden files. For our purposes today, they don’t matter so don’t worry about it if you don’t see them.

Now we need to hook our unit tests up to MySQL so that it can create dummy data for us to test against. Open up the wp-config.php file for your WordPress installation now because you’re going to need to find the db_user and db_pass for the next command.

To finish installing the tests change to your plugin directory and run the following command.

bin/ <db-name> <db-user> <db-pass> localhost latest

Make sure you use a different db-name than your WordPress install. You don’t want your unit tests messing with your data, you want it creating its own test data in its own database. Otherwise, the db-user and db-pass will be the same as your wp-config.php file.

The final two parameters tell the testing framework to connect to localhost and to install the latest version of WordPress to test with. Unless you know better, just leave those settings as they are.

If we were to run phpunit now, we’d still have a few errors to resolve. First, for some reason WP CLI doesn’t add the name attribute to the <testsuite> block in the sample tests. Open phpunit.xml.dist and change <testsuite> to <testsuite name=”Unit Tests”> and save the file.

Also note here that inside the <testsuite> block PHPUnit is told to ignore the tests/test-sample.php file. Let’s duplicate that file and rename it to test-nexcess.php so that we have a file which will run. Then open the new file and change the class name to NexcessTest. The file should look like this now.



 * Class NexcessTest


 * @package Nexcess_Unit_Tests



 * Sample test case.


class NexcessTest extends WP_UnitTestCase {


     * A single example test.


    public function test_sample() {

        // Replace this with some actual testing code.

        $this->assertTrue( true );



Now we’re ready to run phpunit from the terminal. Once you’ve done that you should see something like the image below.

Now that we’ve confirmed that PHPUnit is running our tests, let’s dive a little deeper and write a test to make sure that WordPress is adding users properly.

setUp and tearDown

Most unit tests will require specific data to be added to the testing database. Then you run your tests against this fake data. To do this you use the setUp and tearDown functions in your testing class.

Let’s create a user and then make sure that the user has the edit_posts capability. Add the following function to the top of your class.

   public function setUp(){

        // make a fake user

        $this->author = new WP_User( $this->factory->user->create( array( 'role' => 'editor' ) ) );


Then add this tearDown function to the end of the class.

public function tearDown(){


        wp_delete_user($this->author->ID, true);


This adds a user with the role of editor before we run our tests, and then removes the user after we’ve run our tests.

Now let’s write a simple test to verify that the user was added properly and has the proper capabilities.

   public function testUser(){

        // make sure setUp user has the cap we want

        $user = get_user_by( 'id', $this->author->ID );

        $this->assertTrue( user_can( $user, 'edit_posts' ), 'The user does not have the edit_posts capability and they should not' );

        $this->assertFalse( user_can( $user, 'activate_plugins' ), 'The user can activate plugins and the should not be able to' );


Above we start by getting the user object based on the fake user we created. We’ll need this object to test our capabilities which we do next with the assertTrue and assertFalse statements.

In this instance assertTrue is expecting that our user_can( $user, ‘edit_posts’ ) returns true. We’re testing to make sure that the user object provided is given the edit_posts capability, as an editor should have. If this were to return false, we’d see the message provided in our unit test output in the terminal.

Next, we test to make sure that the same user doesn’t have capabilities of an admin user. Here we use assertFalse while checking for the activate_plugins capability. This should return false because activate_plugins` is for the Admin role in WordPress not for Editors.

Once you have that code added after your setUp function, head to terminal and run phpunit. You should see 2 tests are okay, with 3 assertions.

PHPUnit considers our testUser function to be a test, and the assertTrue/assertFalse statements inside to be assertions.

What does that factory thing mean?

Before we finish here, let me draw your attention back to our setUp function. Specifically the factory section when we create a new user. 

When you use the WP CLI scaffold, it gives you access to the WP_UnitTest_Factory class. This class is there as a helper to create the data you’ll need to run your tests properly. You can use this factory to create posts, attachments, comments, users, terms, and some other things for WordPress Multisite.

This is not the only tool you can use to mimic WordPress for your tests though. In a future post we’ll look at WP_Mock to test parts of WordPress that the built-in factory doesn’t reach very well.

Today, we covered a fair bit of complex ground as we looked at unit testing your WordPress projects. I know when I started unit testing it looked daunting, but it’s worth it if you want code that works, and lets you know when you’ve broken something, so your customers don’t have to find the problem for you. Over the long-term, you’ll save time and headaches by writing testable code and aiming for decent test coverage in your projects.

Further Resources

Source link