How to Use WordPress Action Hooks in Theme Customization

WordPress child themes give a relatively easy way to customize the look and feel of a theme. If the theme’s options don’t provide you with adequate design choices, you can just add a new rule to the child theme’s default stylesheet file called style.css. But what happens when you also want to modify the theme’s functionality? That is one of the cases when WordPress actions come to your help.

WordPress has become so popular partly because of its high customizability. The WordPress Core is loaded with different hooks that enable developers to modify or enhance the default functionality. Moreover, we are allowed to include custom hooks in our themes and plugins to help other developers to easily adjust our code to their needs.

About WordPress Hooks

WordPress hooks work somewhat similar to real-life hooks in the sense that you can catch the fish you want at the right spot if you properly use them.

You can remove a caught function (e.g. you can remove the WordPress admin bar for low-level users), you can leave it intact and enhance it with your own functionality (e.g. you can add more menus or widget areas to a theme), or you can override it (e.g. you can modify the behaviour of a core function).

There are two different kind of hooks in WordPress: actions and filters. In this post we will take a look at how we can make use of action hooks in theme customization.

How WordPress Hooks Work

To use a very simple language, actions indicate that something has happened during the WordPress page lifecycle: certain parts of the site have been loaded, certain options or settings have been set up, plugins or widgets have been initialized, and so on.

Filters are different from actions in their nature. They are used to pass data through, and modify, manage or intercept it before rendering it to the screen or saving user data into the database.

At every significant landmark of the WordPress page lifecycle there is either an action or a filter hook to which we can add our custom code to modify the default behaviour to our needs.

The certain actions and filters running during a request depend on which page was requested by the user agent: for example in a single post request hooks related to single posts are available, but hooks related to other parts of the site (e.g. the admin area) aren’t.

Find Action Hooks

The Action Reference of the WordPress Codex gives a detailed overview of the actions running through different requests. The important thing is that if we want to accomplish a task we need to hook into the right place, not before or after it, otherwise the action won’t be completed.

So for example if we want to add our Google Analytics code to a site we need to hook our action right before the footer is loaded.

If we speak about theme customization, action hooks can come from two different places: from WordPress Core and the theme itself. There are themes that don’t have hooks at all, but others provide developers with some or many – it’s always the theme author’s choice. The default Twenty Fifteen Theme has only one action hook for footer customization under the name of ‘twentyfifteen_credits’.

If you like to browse source code, you can also find action hooks easily. Action hooks are added to the code with the do_action() WordPress function.

If you run a quick search for the expression ‘do_action’ in a more advanced code editor – like I did in Eclipse below – you can see a list about the spots where you can hook your custom functionality into the core. I searched in the /wp-includes/ folder, but you can also run a search for the /wp-admin/ folder that contains the action hooks related to the WordPress dashboard (admin area).

The good thing is that the names of the action hooks are usually pretty self-explanatory, but there is usually a nice comment inside the code that can give you more knowledge whether the given action hook is good for the reason you want to use it for.

For example the code comment before the ‘widgets_init’ action hook says that it “fires after all default WordPress widgets have been registered”. If you take a peek at the code before this action hook, you can find all the default WP widgets’ initialization before it – so you can be sure that the comment didn’t lie, and if you want to register your own custom widget, this will be the right spot.

In many cases the source code provides us with much more information than the Codex, so it can be a good idea to learn how to quickly navigate in it.

Add Your Own Actions

When you want to add your own action, you need to create a custom function and bind this function to a specific action hook by using the add_action() WordPress function. Custom actions added with the add_action() function are usually triggered on the spot when the core calls the appropriate do_action() function.

Let’s see a simple example.

How To Find The Action Hook You Need

Let’s say you want to add your custom favicon to your site. First, you need to find the right action hook you can bind your own functionality to.

Let’s think. If you wanted to add a favicon to a plain HTML page where would you put it? Of course, you need to place it inside the <head> section of the HTML file with the following markup:

<link rel="shortcut icon" href="/" type="image/x-icon" />

So the action hook you need must be related to the loading of the <head> section.

(1) Open the Action Reference, and see what it has to offer. We are lucky, as if we browse through the actions, we can only find one, wp_head, that based on its name has the possiblity to be related to the loading of the <head> section.

(2) To be sure, let’s check the documentation in the WordPress Codex. The Codex advises that “you use this hook by having your function echo output to the browser”, so right now it seems to be perfect for us. But let’s check it in the source code.

(3) As this hook is not related to the admin area we will need to run our search in the /wp-includes/ folder. If we search for the word ‘wp-head’ we will get many results as this specific action is used by WP Core many times.

We need to look for the spot where it gets defined, so search for the expression do_action( ‘wp_head’. Note that we didn’t finish the parentheses, as we can’t be sure yet if this action has parameters or not.

Eclipse returns only one result that can be found inside the /wp-includes/general-template.php file. The comment before the action hook definition says that it “prints scripts or data in the head tag on front end”, so now we can be dead-sure that wp_head is the action hook we need.

Checking For Parameters

When you add your own actions you also need to be sure if the hook you want to use takes parameters or not. You can easily find this out by looking at the do_action() function.

The syntax of the do_action() function is the following:

do_action( 'name_of_action'[, $parameter1, $parameter2, ...] )

Only the name of the action is required, the parameters are optional. If you find arguments in the relevant call of the do_action() function, you need to include them in the declaration of the custom function you create.

If you don’t find any, then your custom function must work without arguments. In the do_action() definition of the wp_head action hook, there are no parameters.

Let’s compare it to an action hook that takes a parameter. The action hook called ‘wp_register_sidebar_widget’ takes one parameter that you always have to pass to the custom function you bind to the hook.

Let’s see the difference in the do_action() syntax of the two cases:

do_action( 'wp_head' );
do_action( 'wp_register_sidebar_widget', $widget );

In the first case there’s no parameter, so the custom function will use the following syntax:

function my_function_without_parameters() { ... }

In the second case there is one parameter that you always have to pass as an argument into the declaration of your custom function:

function my_function_with_parameters( $widget ) { ... }

How To Hook Your Custom Function In

Now we know everything we need. Let’s create our custom function that will display a favicon on our site.

First, create a new function without any arguments, then bind it to the wp_head action hook with the help of the add_action() WordPress function.

function custom_add_favicon() {
echo '<link rel="shortcut icon" href="/" type="image/x-icon" />';
add_action( 'wp_head', 'custom_add_favicon');

You need to pass the name of the action hook to the add_action() function as an argument first, then you need to add the name of your custom function.

These are the two required parameters of add_action(). It has two optional parameters too, priority and accepted arguments. Let’s see how to use these.

Define Priorities

It happens in many cases that there are more than one action bound to the same hook. So which one will be executed first? This is where we can use the $priority optional parameter of the add_action() function.

We add the priority as a positive integer, the default value being 10. If we want an action to be executed early, we give it a lower value, if we want it to be executed later, we give it a higher value.

So if we think that the favicon needs to be there early, we can enhance our previous add_action() call in the following way:

add_action( 'wp_head', 'custom_add_favicon', 5);

Please note that the priorities always have to be set relatively to the other custom functions that use the same action hook.

Add The Number of Accepted Arguments

You are required to add the number of accepted arguments in case you use an action hook that takes parameters. Let’s see the example we used before.

The action hook ‘wp_register_sidebar_widget’ takes one parameter, so when we bind our custom function to this hook, we also need to include this as an argument when we call the add_action() function.

Our code in this case will look like this:

function my_sidebar_widget_function( $widget ) {
// Your code
add_action( 'wp_register_sidebar_widget', 'my_sidebar_widget_function', 10, 1);

Note that we must also add the priority (we chose the default 10 here) to make sure that WordPress knows what each parameter means. If we omitted the priority, WordPress could suppose that 1 is the priority which is not true, as it indicates the number of the accepted arguments.


You can make many experiments with action hooks in theme customization. For example you can add your custom scripts (JS) and styles (CSS) with the wp_enqueue_scripts action hook, or your Google Analytics code with the wp_footer action hook.

You not only can add your own actions, but you can also remove complete functionalities from the WordPress core with the use of the remove_action() function that uses the same logic as add_action().

If you are a theme author, and you want to make an extensible theme, it can be a good idea to add your own custom action hooks to the appropriate template files with the do_action() function.

If you want to do so, think carefully about parameters that other developers who will use your theme will have to pass as arguments when they want to hook in their custom functionalities.

While designing the locations of your theme’s custom action hooks don’t forget that it does not make much sense to include custom theme hooks on the same spots where the WordPress Core itself has its own hooks.

15 wp-config Snippets to Configure WordPress Site

WordPress admin makes it easy to manage configurations without touching a line of code. These basic configuration settings are then stored in the wp-options table inside the database. But, WordPress also has a separate configuration file, called wp-config.php, that can be used for further customizations.

Wp-config is the file where your custom hosting data (database name, database host, etc.) is saved when you install a self-hosted WordPress site. You can also add other configuration options to this file, with which you can enable or disable features such as debugging, cache, multisite, SSL login, automatic updates, and many others.

Localize and edit wp-config

When you download WordPress, the wp-config.php file is not yet present inside the install folder. However, there’s a file called wp-config-sample.php that you need to copy and rename to wp-config.php. Then, you need to add your basic connection data (database name, database username, database password, hostname, security keys) to this file.

If your hosting provider uses the Softaculous auto installer (most do so) this process is automated for you and you will find a wp-config.php and a wp-config-sample.php file in your root folder when you connect your server via FTP.

Note that the order of settings matters, so don’t rearrange them. When editing the wp-config file, always use a code editor such as Sublime Text, Atom, Notepad++, Visual Studio Code, or TextMate. Word processors (Microsoft Office, Google Docs, LibreOffice, etc.) will mess your file up, never use them to edit code files.

The settings saved into wp-config override the database, in case the same type of configuration is present at both (e.g. home URL)

Where to place the code snippets

In this article, you can find 20 code snippets with which you can use to customize your wp-config.php file.

Most of these configuration options don’t exist in wp-config by default. If you want to use them you need to add them below the starting <?php tag and code comments, but above the MySQL settings.

1. Turn on WP debugger

You can turn the WordPress debugger on and off in the wp-config file. The first snippet below does exist by default in wp-config (below the database configurations) but its value is set to false. To turn the debugger on, change its value to true.

The second snippet turns on the frontend debugger that allows you to debug CSS and JavaScript scripts. Use the debuggers only on development sites never in production.

More Than Page Ranking: Working with Clients on SEO Basics

Somewhere deep in the darkest vaults of the Googleplex, robed figures make dark incantations to the eldritch god Algorithm. Secret rituals create mysterious results, impossible for mere mortals to understand.

At least, that’s the way SEO can seem to your clients.

But the basics of SEO are really quite simple, straightforward, and – dare we say – ordinary.

When you’re embarking on any web project with a client, it’s crucial to be mindful of SEO. And by establishing a clear and focused SEO strategy, you’ll maximize your project’s impact.

Changing the Misconceptions About SEO

Too long. Too expensive. Too random. Too hopeless.

While most clients understand the value of well-executed SEO, it’s not uncommon for them to get overwhelmed and dismiss a concentrated effort.

Maybe that’s why they’re looking for your help in the first place! It might even be tempting to lean into the misconceptions about SEO and portray yourself as a kind of sage SEO wizard with special, secret insights.

Ultimately though, you’ll drive better results and a stronger relationship by giving your client clear insights. Empower them, and they’ll more easily see the value you provide as well. And that starts with making clear that your SEO strategy isn’t some weird extra, but actually an already interlinked piece of any site’s build.

Most SEO Best Practices Easily Align with Your Project

In practice, SEO’s crucial basics line up like natural guideposts in building a site anyway.

Here’s a summary of pretty much everything a search engine wants in a top-ranking result:

  • Provides useful, accurate information
  • Follows a clear structure and purpose
  • Loads and performs reliably
  • Engages the visitor and fulfills their need

Sounds a lot like the goals of any design or content project!

Search engines want to connect their users with useful, engaging content that’s tightly associated with the users’ searches. So their algorithms have been rooted in human behavior: They seek traits that consistently correlate with better experiences for users.

In a lot of ways, SEO best practices can act as a checklist for building an amazing user experience. And great UX generates more conversions, repeat visitors, lower bounce rates … Even if a site doesn’t get a single visitor from organic search (it will!), it would still benefit from embracing SEO guidelines.

SEO is Never Hopeless

If you’re looking to outrank a giant, global conglomerate for their brand’s specialty, you’ve likely got a lengthy, costly, and chancy challenge ahead of you.

It’s worth pointing out: You can topple giants. Relatively small companies get top ranks for general search terms that you’d expect multi-billion-dollar businesses to control all the time. But those lofty Don Quixote goals will most likely take time and a concentrated, precision effort.

More importantly: The specific keywords – the ones related to the specialization and differentiation that make a business viable – are very ownable with a solid execution of the basics. And those will generate valuable organic search traffic.

So, when you begin discussing SEO with a client, don’t get lost in the weeds. If you let tiny technical tweaks tangle up your client – especially at the onset – the big simple elements can feel complicated too.

The Most Essential SEO Basics for Your Clients

Most basic SEO strategies follow a similar blueprint.

You’ll likely still perform specialized optimizations based on individual site needs. But having the essential foundation in place will always be crucial. So, start with these.

Determine Target Keywords

Keywords form the cornerstone of any SEO strategy. And in the big picture for a client’s business, target keywords reflect a site’s overall messaging and content strategy.

What defines the business in the eyes of its customers? What elements of the brand story are most likely to pull in visitors? What problems does the business best solve?

The client’s natural answers to these questions provide the framework. From there, SEO keyword research tools help quantify the current strengths, opportunities, and gaps across three fronts.

  • Internal – What terms already drive traffic to a business? Tools like Google Search Console focus on these.
  • External – What terms could help a business pick up new traffic? This is the bread-and-butter of tools like Google Keyword Planner.
  • Related – What terms and phrases are you missing? Tools like Entity Explorer and Also Asked help on this front.

By examining these three groups together, you and your client can prioritize keywords across the site experience. This list will be critical in everything that follows.

Different types of keywords can be used for unique purposes. In fleshing out an SEO strategy, you’ll want to understand the nuances. But again, be careful about making the main task too complex for clients at the onset.

Utilize Keywords in Page Content

Once you identify the target keywords for a site, you need to put them to use.

With your target keywords spread throughout web-page copy, you signal that those pages have information related to a customer’s search. Make sure you’re thinking about all these:

  • Headings
  • Body copy
  • Title
  • Meta description
  • Alt tags on images

At the base level, these instances represent the biggest factor search engines look for: A simple statement of what page content is about. Again, totally logical.

A snowball effect can occur after that. Search visitors who engage longer with a page signal to search engines that the site is a high-quality resource, improving search ranking even more.

Some clients might bristle at the idea of stocking pages with target keywords, worried about the prospect of keyword stuffing overtaking their brand story. (And others might get over eager to do exactly that!)

So, in your communication, emphasize that the experience still matters first and foremost. The goal here is to make it easier for visitors and search engines to recognize the content that’s relevant to them … and overstuffing often makes that less clear.

Link Related Products and Content

The web gets its name from its vast network of links and connections. And that fundamental nature matters with SEO as well: Build web site pages so they fit into the bigger story of a brand and its industry.

This typically starts with internal linking. By creating links to other related pages and content on a site, you build a depth of authority in the eyes of visitors – and search engines.

External linking will be a major factor as well. Connections with sites that are already viewed as authorities in turns builds the perception of your site’s authority. The basic concept here is something every marketer – and even networking business professional – will be familiar with.

Another warning for the overzealous: Avoid paying for links. Connecting with spam sites can actually penalize your content.

Quality linking increases engagement, too. So these efforts impact SEO from multiple angles. Just the kind of thing you’re looking for in a simple SEO strategy!

Set Realistic Targets and Goals

SEO takes time to deliver results, and even lower rankings will still generate traffic for a site.

You can alleviate many clients’ immediate concerns with monthly reports, demonstrating improvements in ranking and the direct result of your SEO efforts. And highlight the general improvements in site navigation and experience that SEO best practices create.

By reinforcing the deep and wide benefits of SEO, you’ll ensure you stay on the same page as your client throughout the project.

Displaying Custom Post Types – Templates and Querying

This is the 3rd and final article of our series on Custom Post Types (CPT). The topics we discussed in the first two were:

In the first and second articles, we registered the testimonials custom post type and the testimonial_service custom taxonomy. We now have to display the testimonials on our site. So we will take a look at how to create a template for our testimonials, how to query them, and how to display them anywhere on our site.

Default Custom Post Type Templates

We created our CPT with the parameter has_archive set to true, which will display all testimonials in an archive page.

WordPress uses a template hierarchy to display different types of content. For the custom post type, it will look for:


If these templates are not defined in the theme, then it will look for the general templates:


If even these templates are not defined, then it will default to the index.php template.

In our case the Shaka theme has the single.php, but does not have the archive.php template. This means that it will, by default, use the single.php template for the single testimonial page. It will also use the index.php template to display all testimonials in the testimonials archive page.

The testimonials will be displayed in the testimonials archive page, which will be located on this page:

If you have the pretty permalinks enabled, then you can also access the page with this URL:

(Note: if the pretty permalinks are not working for you, go to wp-admin -> Settings -> Permalinks and set them up, the way you want them and save the settings)

First, we should write some testimonials in the newly registered CPT Testimonials, so we have some data to display. I’ve added 3 testimonials and this is how the default layout of the testimonials archive page looks on our Shaka theme:

As you can see the layout is ok, but some of the data displayed is not needed, like the “by author” and the date. Also the testimonial_service custom taxonomy is not displayed, so we will add that in our custom templates.

Creating custom templates for our CPT

As mentioned in the previous section, we have to create two templates. The archive-testimonials.php and the single-testimonials.php. We will only create the archive-testimonials.php template for this example.

We should create these files in a child theme, but for the sake of simplicity, I’ll add the archive-testimonials.php file directly in the Shaka theme. I’ll copy the index.php file, which will serve as a starting point, and rename it to archive-testimonials.php.

I’ve removed the “by author”, the date code, and the sidebar. I have added the featured images and the testimonials service custom taxonomy. I’ve used the the_terms WP function that displays a list of specific WP terms, in our case the custom taxonomy.

I know that aesthetically it does not look awesome, but that’s not the point. We wanted to create a different structure/layout of the testimonials archive page with different data, and that was achieved in a few minutes.

We could also do the same for the single testimonials page. We would copy the single.php file and rename it to single-testimonials.php and change the code from there.

I didn’t show any code here as the code examples would be different for each theme and some basic knowledge of HTML and PHP is needed to code templates. But it’s always easier to modify an existing template, that’s why we used the index.php as our starting point.

Querying Custom Post Types

Another way to display custom post types on your site is to use the WP_Query class to fetch the custom post types (loop through and display them).

Let’s say you want to build a widget that displays all testimonials in a carousel. Or, that you would want to display related testimonials (same testimonial service taxonomy) on the single testimonial page. You would use the WP_Query class to retrieve the relevant testimonials.

In our example we will fetch all the testimonials that are in the “diving” testimonial service custom taxonomy and we’ll output them in a list:

$args = array(
  'post_type'   => 'testimonials',
  'post_status' => 'publish',
  'tax_query'   => array(
  		'taxonomy' => 'testimonial_service',
  		'field'    => 'slug',
  		'terms'    => 'diving'
$testimonials = new WP_Query( $args );
if( $testimonials->have_posts() ) :
      while( $testimonials->have_posts() ) :
          <li><?php printf( '%1$s - %2$s', get_the_title(), get_the_content() );  ?></li>
else :
  esc_html_e( 'No testimonials in the diving taxonomy!', 'text-domain' );

As you can see in the code above, we first prepare the array of argument settings, that is later used in the WP_Query initialization. In this array, we define to retrieve:

  • `testimonials` CPT,
  • get only the testimonials that are published,
  • get only the testimonials that are in the diving custom taxonomy `testimonial_service`.

When the new WP_Query is called, the relevant testimonials are retrieved and we can loop through them. In the loop we simply output the title (which I used for the author name) and the content of the testimonial in a simple list. Also, we should always use the wp_reset_postdata function, to reset back to the original loop, when we use a WP_Query loop. This will ensure that everything works after we finish with our custom query.

These have been the basics of Custom Post Types, and I hope you now understand how they work. As with any topic, there are always more details to go into. I would advise you to go through the official WP documentation for all the functions and classes we used in these examples. Let me know in the comment section below, if you have any questions.

A Quick (and in-Depth) Guide to WordPress Hooks

WordPress hooks are the thing to learn if you want to get into WordPress development. Hooks allows you to do two things: change default functionality within WordPress and add your own functionality without modifying core WordPress files at all.

Making sure you never modify core files is extremely important, but modifying and adding stuff seems impossible without it.

In this post, I’m going to show you how you can do it pretty easily with two types of hooks: actions and filters. You’ll need a basic understanding of HTML and PHP for this one, but not too much. Let’s dig in!

The Need for Hooks

Hooks are built into WordPress and are used to modify or add functionality to the core system. Let’s assume for a moment that WordPress does not provide any hooks. And let’s also say you work with a lot of scheduled posts and you would like to email yourself when a post is published. How would you go about doing that?

Without hooks you would need to modify core files. You would hunt down the code that is responsible for publishing a post and just after the function that performs the action, you would paste your own code.

This is detrimental for a number of reasons. The two big ones are updates and uncontrollable code. If you modify core WordPress files your code will work just fine but will be erased when you update WordPress to the next version. You would have to remember or track all of your changes and then put them back in. Not exactly convenient. Alternatively, you could simply not update WordPress, but that would be a huge security risk in the long run.

Even if you do manage to keep track of changes and update WordPress, you are left with a non-standard environment with uncontrollable code. Other WordPress developers will have a hard time dealing with your code, and the community as a whole will not be happy.

Enter Hooks

A hook does almost exactly what we talked about before (find the place where a post is published, paste your code), but replaces the horrible pasting bit with a placeholder. By default, there is a placeholder after the post publishing function, which allows you to tie functionality there. Here’s a shortened version of the actual wp_publish_post(), which you can find in wp-includes/post.php.

function wp_publish_post( $post ) {
  // Stuff that actually published the post  
  do_action( 'wp_insert_post', $post->ID, $post, true );

That do_action() bit basically says: You can tie your own function to me, they will all be executed. So whenever WordPress publishes a post using the wp_publish_post() function it goes through all the necessary steps to make it happen. It then moves on to the do_action() function. It’s first parameter is wp_insert_post. Any function which is tied to this wp_insert_post action will get executed.

Let’s look at an example.

To create a hooked function you need to create a simple plugin, use your theme’s functions.php file, or create a child theme and use the functions.php file in there. Let’s create a quick plugin now.

Create a new folder in the Plugins directory and name it “hook-example.” Create a “hook-example.php” file within that directory and paste the following code into it:

 * Plugin Name: Hook Test
 * Description: A simple plugin to test hooks

Your plugin is now ready. Head on over to the Plugins section in WordPress admin and activate it. Now let’s create a hooked function. In the hook-example.php file, paste the following:

add_action( 'wp_insert_post', 'email_post_author', 10, 3 );
function email_post_author( $post_id, $post, $update ) {
  $email = '';
  $subject = 'New Post Published';
  $message = 'A new post was published, use this link to view it: ' . get_permalink( $post->ID );
  wp_mail( $email, $subject, $message );

We’re using the add_action() function to let WordPress know that we’d like to hook a function into wp_insert_post. The second and third parameters are the priority and the arguments. We’ll get into that soon.

In our hooked function we simply define what we’d like to do. In this case send an email to ourselves. Whenever WordPress published a post it will look for all functions hooked into wp_insert_post and run them all.

So what have we achieved here? We’ve added functionality to a core part of WordPress without actually modifying the core files. All we needed was one extra line of code. This is very important! All you need to do is write a function that does what you need, then you hook it into a specific part of WordPress.

Actions and Filters

So far we’ve seen what an action is – it’s a piece of code that is executed at a specific time. A filter can be used to modify content before WordPress uses it. You could use a filter to modify the “your password is incorrect” text on the login page. Let’s take a look at wp-login.php:

if ( ! empty( $errors ) ) {
	 * Filter the error messages displayed above the login form.
	 * @since 2.1.0
	 * @param string $errors Login error message.
	echo '<div id="login_error">' . apply_filters( 'login_errors', $errors ) . "</div>\n";

The snippet from the actual file that handles logins shows that login error messages are displayed using an apply_filters() function. This is very similar in logic to the do-action() function.

My second parameter contains some sort of data. If you use a hooked function based on my first parameter you can modify this data, otherwise I’m going to use it as is. By default, if you enter a correct username but incorrect password you see the following notice:

If you think this is a bit unsafe because it exposes the fact that the username is correct you can hook a function to login_errors to modify it. Here’s how:

add_filter( 'login_errors', 'modify_login_errors' );
function modify_login_errors() {
    return 'Login unsuccessful, try again';

By implementing this change you’ve added a bit more security to your login process and you can also control the text.

Hooks, Actions, Filters, Hooked Function and Tags

There is some confusion about these terms above because sometimes they are used interchangeably. I myself mis-speak sometimes, so let’s get things straight just in case I mess up further down!

Hook is an umbrella term for actions and filters. Actions allow you to add your own functionality next to existing functionality. Filters allow you to modify existing functionality. Sometimes the word tag is used to refer to the string that indicates where you are adding your hook. A hooked function is a function you create that adds or modifies functionality.

The Anatomy of a Hook

When we use hooks we generally rely on two functions: add_action() and add_filter(). Both these function take four parameters:

  1. The first parameter is the tag. This is the bit that tells WordPress where to hook your function, when it should be executed.
  2. The second parameter should be the name of the hooked function.
  3. The third parameter is the priority of the hook. This determines the order in which it is executed if multiple functions are hooked into the same tag.
  4. The fourth parameter defines the number of parameters passed to this function. By default this is 1, but some tags (like the previous wp_insert_post) can have more.


The first parameter of both functions is a simple string that states when the hooked function is executed. There are many, many tags you can use. There are action tags that run when posts are deleted, categories are created, a user is logged in and more. Filter tags are run on messages for custom taxonomies, post title displays, dates and more. The Hooks Reference is a good place to start, but sometimes a Google search can be more effective!

Note that some tags may be referred to as variable hooks. There is a hook named “{old_status}_to_{new_status}” for example. This hook simply means there are a number of hooks defined for combinations. publish_to_trash would run when a publish post is trashed, future_to_draft would run when a scheduled post is set to draft status.

Hooked Function

Again, a simple string, which should be the exact name of the function. Since this will be a function name it should contain letters, numbers and underscores only.

Take extra care to make this function unique. If you name a function “send_email” it may clash with someone else’s function of the same name. It is common practice to prefix function names, something like: my_send_email, or wpmudev_send_email.

I also advise making your function names readable. You could name your function sae(), short for “send author email” but this is extremely bad practice as no one else will know what this means, and you will probably forget in a few months as well.

Hook Priority

The third function defines the priority of a hook. The lower the priority the sooner the function gets executed. In some cases the order is not important but in some cases it is essential. If you want to send a post publication email to yourself and the author, the order doesn’t much matter. You can use the default of 10 for both:

add_action( 'wp_insert_post', 'send_author_email', 10, 3 );
add_action( 'wp_insert_post', 'send_admin_email', 10, 3 );

However, if you would like to update some statistics whenever a post is updated and then notify the author the order suddenly becomes important:

add_action( 'save_post', 'send_admin_email', 10, 3 );
add_action( 'save_post', 'update_post_stats', 5, 3 );

As you can see, the order in which the add_action() calls are places is not important. The second call has a lower priority, therefore it will be executed first.

For filters you need to be more careful. Since filters modify data they may overwrite each other. If two filters are hooked into the same tag, the one with the lower priority is executed first. Then, the one with the higher priority is executed which may change the data completely. Many times this is desirable behavior, it’s just something to be aware of.


The fourth parameter sets the number of parameters passed to our hooked function. This is something you will need to hunt down as it depends on what is in the source code.

If you go back to see how we changed the login errors you’ll notice the following function: apply_filters( 'login_errors', $errors ). The first parameter is the tag, the rest are arguments. There is only one here, so one argument is passed to our hooked function.

In case of wp_insert_post() you can see the following in the core files: do_action( 'wp_insert_post', $post->ID, $post, true );. The first parameter is the tag, the rest are arguments, so the value here is 3.

Our Own Hooks

The great thing about the hooks system is that we can create our own. All we need is the two familiar functions we’ve seen: do_action() and apply_filters()

Let’s create our own filter for a plugin which displays products. In the footer we could write: “Thanks for using our product display plugin,” which we would allow developers to modify.

Here’s how that can be done:

<p><?php apply_filters( 'product_display_footer', 'Thanks for using our product display plugin' ) ?></p>

Actions can be added the same way. You may want to allow users to add some content below the description of a product display:

<h1><?php the_title() ?></h1>
<div class="description"><?php the_content() ?></div>
<?php do_action( 'below_product_description', $post ) ?>

I’ve used the do_action() function to allow others to modify my functionality. I’ve also added the post object as the first parameter, just in case people want to add some post-specific content.


In this article we looked at the basics of hooks. We learned the difference between actions and filters and how to use them to effectively change the way WordPress works.

We also had a look at how we can add hooks of our own to our plugins and themes. This is immensely useful for making our work developer friendly.

Hooks are a part of the Plugin API, if you want to learn more about them I suggest reading the relevant pages in the WordPress Codex. The more you use hooks the more you’ll love them and appreciate the power and flexibility they offer.

Adding Custom Meta Descriptions to WordPress Posts Without Using a Plugin

It is true that meta descriptions no longer play a role as a ranking factor, but they still hold a lot of value. This is considering the fact that Google and other search engines use meta descriptions in their SERPs (search engine result pages) which makes meta descriptions a great way to attract user attention and make them click on your listing.

Adding Meta Descriptions to WordPress Posts

By default wordpress does not have a field that allows a user to add a meta description, but this can be easily achieved using custom fields and then calling this field from within the head section when a page loads. The following are the steps required to achieve this:

  1. Create a custom field using the wordpress dashboard
  2. Edit your theme’s functions.php page and add a function to call this custom field.

Let’s see how this can be done in details:

1.) Creating the Custom field

The first step is the create a custom field. This can be done as follows:

Step 1: Login to your wordpress dashboard.

Step 2: Create a new post or open an existing post to which you need to add a meta description.

Step 3: Make sure that custom fields are being displayed. If not, click Screen Options located in the top right corner of your dashboard and make sure the check-box next to custom fields is checked as shown in the image below.

Step 4: Scroll down to the bottom of the post editor and you should now be able to see a Add New Custom Field area.

Step 5: Click Enter new and in the Name section write down the text description and in the Value section write down the custom meta description of the respective article as shown in the image below.

Step 6: Click on ‘Add Custom field’.

Now the next step is to create a function that calls this custom field and outputs it in the head section of the site. Remember that the name of the custom field we need to call is description (all lower caps).

2.) Adding the Function to Functions.php

Open your theme’s functions.php page and add the following code to it:

/*Display custom meta description or the post excerpt */
function add_custom_meta_des(){

#Homepage Meta Description
if( is_home() || is_front_page() ){
	$meta_des = "Enter your homepage meta description here"; #Edit here
	echo '';

#Single Page Meta Description
if( is_single() ){
	$des = get_post_meta( get_the_id(), 'description', true);
	if( ! empty( $des )  ){
		$meta_des = esc_html($des);
		echo '';
add_action( 'wp_head', 'add_custom_meta_des', 4 );

This is how the above code works:

  • The first line of the code checks if the current page is the homepage and if yes, displays the meta description entered in the code.
  • If it is not the homepage the code checks if the page is a single post page and if yes, it checks if the page has a custom field named description and outputs the custom field if present. If not present, it outputs nothing.

So this is how easily you can displays custom meta tags in your posts. You can also use the same code to display meta keywords and other related meta tags. If you have any questions, feel free to leave it in the comments below.

Πώς να δημιουργήσετε Virtual Hosts στον Apache σε Debian 8

Το Virtual Hosting είναι ένας τρόπος hosting πολλών διαφορετικών domain names σε έναν φυσικό server . Επιτρέπει το μοίρασμα των πόρων του φυσικού server πχ cpu , ram ,  στα διάφορα domain names .

Παρακάτω θα φτιάξουμε ένα  setup για τα domain names , , .

Αν το apache δεν είναι εγκατεστημένο στο σύστημα σας χρησιμοποιήστε την apt -get για να το εγκαταστήσετε :

sudo apt-get update
sudo apt-get install apache2

1.Δημιουργία των directories

Αρχικά το directory  /var/www/html  είναι το default του web server  . Εμέις θέλουμε να δημιουργήσουμε ενα directory για το κάθε domain name , και για κάθε domain name , έναν φάκελο που θα έχει τα αρχεία του . : 

sudo mkdir -p /var/www/
sudo mkdir -p /var/www/ 

Τώρα δημιουργήσαμε αυτούς τους φακέλους , αλλά μόνο ο χρήστης root έχει δικαιώματα . Για να δώσουμε δικαιώματα στον απλό χρήστη χρησιμοποιούμε τις εντολές :

sudo chown -R $USER:$USER /var/www/
sudo chown -R $USER:$USER /var/www/

 Όπου user το όνομα του χρήστη στον οποίο θέλουμε να δώσουμε δικαιώματα .

2.Δημιουργία demo σελίδας σε κάθε Virtual Host

Τώρα αφου τα directories είναι έτοιμα , θα βάλουμε στον φάκελο του κάθε virtual host μια πολύ απλή σελίδα index.html . Αυτο θα βοηθήσει αργότερα όταν θα χρειαστούμε να τεστάρουμε τους virtual hosts .

sudo vi /var/www/

Το index.html θα είναι ένα πολύ απλό html page που απλά θα δείχνει ότι είμαστε στο σωστό directory .


   <title>Welcome to!</title>
   <h1>Success! The virtual host is working!</h1>

Επαναλαμβάνουμε ακριβώς την ίδια διαδικασία και για το domain name test2

sudo vi /var/www/


   <title>Welcome to!</title>
   <h1>Success! The virtual host is working!</h1>

3.Δημιουργία νέων Virtual Host files

Τα Virtual Host Files προσδιορίζουν τις ρυθμίσεις λειτουργίας των virtual host μας , και ρυθμίζουν πως θα απαντά ο server  στα αιτήματα που του γίνονται . 

Ο Apache έχει ένα default virtual host file που λέγεται 000-default.conf και μπορούμε να το χρησιμοποιήσουμε για να φτιάξουμε τα δικα μας  αρχεία .

sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/

 sudo vi /etc/apache2/sites-available/

Με κάποιες μικρές διαφορές το αρχείο πρέπει να έχει την παρακάτω μορφή


<VirtualHost *:80>

       ServerAdmin webmaster@localhost
       DocumentRoot /var/www/html

       ErrorLog ${APACHE_LOG_DIR}/error.log
       CustomLog ${APACHE_LOG_DIR}/access.log combined


Για αρχή θα αλλάξουμε το email στο πεδίο Serveradmin έτσι ώστε ο admin του server να μπορεί να δέχεται email .

Μετά , κάτω απο την γραμμή του email θα προσθέσουμε 2 νέες πεδία :



Τέλος , αλλάζουμε το πεδίο DocumentRoot ώστε να δείχνει στο directory που δημιουργήσαμε πριν , δηλαδή το :


Αποθηκεύουμε το αρχείο . Βέβαια φτιάξαμε το Virtual Host File για το domain name test1. Για το domain name test2 θα επαναλάβουμε ακριβώς την ίδια διαδικασία .

4.Ενεργοποίηση των Virtual Host files 

Ως τώρα έχουμε δημιουργήσει τα virtual host fiiles σύμφωνα με τις ανάγκες μας , αλλά ο apache δεν πρόκειται να τα χρησιμοποιήσει , αν δεν τα ενεργοποιήσουμε πρώτα .

Ενεργοποιούμε με την σειρά το καθε domain name :

 sudo a2ensite

 sudo a2ensite

Το a2ensite είναι ένα εργαλείο για την ενεργοποίηση των sites .

Αφου εκτελέσουμε τις 2 απο πάνω εντολές θα πάρουμε λογικά την ακόλουθη έξοδο :

Enabling site
To activate the new configuration, you need to run:
 service apache2 reload

Θα χρειαστεί να κάνουμε reload τον Apache , αλλά πριν γίνεται αυτό πρέπει να κάνουμε disable to 000-default.conf μιας και πλεον χρησιμοποιούμε τα δικά μας configuration files .

sudo a2dissite 000-default.conf

Τώρα είμαστε έτοιμοι να κάνουμε reload τον Apache

sudo systemctl restart apache2

5.Test των αποτελεσμάτων

 Για να είμαστε σίγουροι   ότι δεν κάναμε κάποιο λάθος , θα ανοίξουμε εναν browser , και θα δοκιμάσουμε να μπούμε στα 2 site που δημιουργήσαμε πριν , τα :

Αν δούμε το μήνυμα Sucess!The virtual host is working και στις 2 σελίδες όλα έγιναν σωστά και είμαστε έτοιμοι!

How to host multiple websites on Apache2

If Apache has been your web server of choice for years, and you’re finally migrating to Apache2, it’s time to learn a new trick: setting up multiple virtual hosts with Apache2.

If you’re a Linux system administrator, chances are you’ve worked with Apache. And if you’ve done enough Apache configuration, you’ve most likely set up virtual hosts. But if you’re finally migrating away from your old Apache-powered web platform and onto Apache2 (the version of Apache shipped with the likes of Ubuntu Server), you’ll need to change your way of thinking.

I’ll walk you through the process of hosting multiple websites (aka virtual hosts) on an Apache2-based system (in this case Ubuntu 16.04). Believe it or not, it’s simple…you just have to know what to configure and where to configure it.

I assume you already have Apache installed and, if you point your browser to the server IP (or domain), either the Apache2 welcome page or your company site will appear. Let’s add yet another site to your Apache2 server.


With Apache2, all virtual hosts are configured in individual files with /etc/apache2/sites-available. Each file will end in .conf and contain all of the details for the host. An example .conf file will look like:

Τι είναι τα VirtualHosts

Αρκετοί είναι οι χρήστες που εγκαθιστούν τον Apache Web Server στον υπολογιστή τους για να αρχίσουν να μαθαίνουν Web Development ή για να κάνουν τοπικά την παραγωγή των έργων τους. Αλλά γνωρίζουν πως να φτιάξουν VirtualHosts με XAMPP και Apache;

Το πρόβλημα με την τοπική εγκατάσταση του Apache είναι πως η προκαθορισμένη μορφή εγκατάστασης δεν επιτρέπει την δημιουργία VirtualHost* και έτσι όσοι χρήστες εγκαθιστούν νέα έργα στην προκαθορισμένη εγκατάσταση έχουν URLs της μορφής ή http://localhost/project-name/ κάτι που δεν είναι και τόσο κομψό και εύχρηστο.

Σε αυτό το tutorial, θα σας εξηγήσω τι είναι τα VirtualHosts και θα σας δείξω πως να ρυθμίσετε τον XAMPP (μπορείτε να ακολουθήσετε τα ίδια βήματα και σε αυτόνομες εγκαταστάσεις Apache) για να υποστηρίξει VirtualHosts ώστε να έχετε τα project σας συγκεντρωμένα κάτω από ένα φάκελο στο σύστημα σας, και να έχουν όλα σας τα έργα το δικό τους domain. Έτσι, αντί να έχει το έργο σας το domain ή το http://localhost/project-name/ να έχει το domain

Τι είναι τα VirtualHosts

Τα VirtualHosts είναι η διαδικασία κατά την οποία ο Apache Web Server μπορεί να εξυπηρετήσει περισσότερα από ένα καταλόγους (φακέλους) ως ξεχωριστούς “hosts”.

Ουσιαστικά αυτή η διαδικασία είναι παρόμοια με το να έχετε ένα υπολογιστή για κάθε έργο σας, με τη διαφορά που όλα τα έργα σας εξυπηρετούνται από τον ίδιο φυσικό υπολογιστή.

Τύποι VirtualHosts

Ο Apache υποστηρίζει τους ακόλουθους τύπος VirtualHost.

  • Name Based VirtualHosts
  • IP Based VirtualHosts

Name Based VirtualHosts

Οι Name Based VirtualHosts, είναι η ποιο απλή μορφή VirtualHost και σας επιτρέπει να κάνετε αντιστοίχηση ενός καταλόγου σε ένα domain.

Έτσι, αν για παράδειγμα έχετε τα ακόλουθα έργα:

  • C:\htdocs\Project1
  • C:\htdocs\Project2
  • C:\htdocs\Project3

Μπορείτε με Name Based VirtualHosts να κάνετε ανάθεση ενός domain ανά κατάλογο, και στη συνέχεια να προσπελάσετε το κάθε έργο μέσω του Domain του.

Έτσι, αν υποθέσουμε πως έχετε τους παραπάνω καταλόγους, τότε μπορείτε να γράψετε τις ακόλουθες εντολές στο αρχείο ρυθμίσεων του Apache (θα σας υποδείξω αργότερα ποιο είναι αυτό το αρχείο) για να κάνετε την αντιστοίχηση των καταλόγων σε domains:

NameVirtualHost *:80
<VirtualHost *:80>
    ServerName www.project-1.ext
    DocumentRoot "C:/htdocs/Project1"
<VirtualHost *:80>
    ServerName www.otherdomain.tld
    DocumentRoot "C:/htdocs/Project2"
<VirtualHost *:80>
    DocumentRoot "C:/htdocs/Project2"

Και έτσι τώρα θα μπορείτε από τον υπολογιστή σας να προσπελάσετε τα τρία αυτά έργα με το domain τους. Για παράδειγμα, για να προσπελάσετε το Project1 θα πρέπει να γράψετε στον Browser σας την διεύθυνση http://www.project-1.ext/ αντί για την διεύθυνση ή την διεύθυνση http://localhost/Project1

IP Based VirtualHosts

Οι IP Based VirtualHosts είναι χρήσιμοι για να μπορέσετε να προσθέσετε διαφορετικές ρυθμίσεις σε ένα host βάση της IP και της θύρα από την οποία πραγματοποιείτε η προσπέλαση του site.

Η ποιο συχνή χρήση αυτού του τύπου VirtualHost είναι για να μοιράσουμε από τον ίδιο Server διαφορετικά Site όταν η προσπέλαση γίνετε από διαφορετικές θύρες ή διαφορετικές κάρτες δικτύου.

Για τον συγκεκριμένο τύπο VirtualHost δεν θα αναφέρω περισσότερα, αφού δεν είναι κάτι το οποίο πρέπει να καλύψουμε σε αυτό το tutorial.

Μειονεκτήματα των Name Based VirtualHosts

Οι Name Based VirtualHosts είναι καλοί για την περίπτωση που θέλετε να βάλετε σε ένα μηχάνημα 5 – 6 ιστοσελίδες με τα δικά τους Domains.

Αν στο περιβάλλων εργασίας που είστε έχετε πολλά έργα ή έχετε σκοπό να δημιουργήσετε πολλά έργα, τότε αυτή η λύση δεν είναι η ιδανική, αφού μετά από κάποιο αριθμό έργον, ο υπολογιστής σας θα αρχίσει να βαραίνει, με αποτέλεσμα να μην μπορείτε να κάνετε την δουλειά σας αποτελεσματικά.

Επίσης, ακόμα ένα μειονέκτημα που έχει αυτή η λύση είναι πως κάθε φορά που δημιουργείτε ένα νέο έργο, θα πρέπει να κάνετε επανεκκίνηση και τον Apache Web Server.

Τέλος, με τους Name Based VirtualHosts ένας αμελής χρήστης μπορεί πολύ εύκολα να χαλάσει την δομή των αρχείων του στον σκληρό δίσκο του, με αποτέλεσμα να είναι δύσκολο να εντοπίσει κάποιο έργο όταν θα έχει μερικές δεκάδες έργων εγκατεστημένα στο PC του.

Λύση στο πρόβλημα

Η λύση στο πρόβλημα είναι να δημιουργήσουμε δυναμικά ρυθμιζόμενους VirtualHosts. Με τον Apache, έχουμε την δυνατότητα να χαρτογραφήσουμε την δομή ενός καταλόγου, και έτσι να έχουμε αυτόματη δημιουργία των VirtualHosts με κοινές ρυθμίσεις για όλους τους hosts που θα προκύψουν.

VirtualHosts με XAMPP και Apache

Ο τίτλος του άρθρου αναφέρετε στον XAMPP γιατί είναι ίσος ο ποιο εύκολος και διαδεδομένος τρόπος για να έχει κάποιος ένας πλήρες περιβάλλον ανάπτυξης ιστοσελίδων στον υπολογιστή του χωρίς να απαιτούνται ιδιαίτερες γνώσεις για το πως να στήσει το απαραίτητο λογισμικό.

Οι πληροφορίες που ακολουθούν είναι κοινές και για εγκαταστάσεις Apache Web Server έξω από το πακέτο διανομής XAMPP.

Στατική IP

Πριν αρχίσετε να κάνετε οτιδήποτε, θα πρέπει να ορίσετε στατική IP στον υπολογιστή σας. Όσοι δεν γνωρίζετε με ποιο τρόπο να κάνετε αυτή την αλλαγή, ακολουθήστε τις οδηγίες στο βίντεο που ακολουθεί (αγγλόφωνο) και δημιουργήστε την IP που επιθυμείτε.

Hosts file

Κανονικά για να μπορέσετε να δηλώσετε τα δικά σας domain θα πρέπει να στήσετε τον δικό σας DNS Server. Ωστόσο αυτή η διαδικασία είναι επώδυνη και απαιτεί αρκετή τεχνογνωσία.

Για να παρακάμψουμε αυτή τη διαδικασία μπορούμε να προσθέσουμε εγγραφές στο hosts file του υπολογιστή μας.

Στο συγκεκριμένο tutorial θα σας παρουσιάσω τον τρόπο με τον οποίο μπορείτε να επεξεργαστείτε και να προσθέσετε νέες εγγραφές στο αρχείο αυτό.

Στα Windows το αρχείο hosts είναι στον φάκελο C:\Windows\System32\drivers\etc\ και δεν έχει κάποια κατάληξη (πχ, .txt, .ini, .sys).

Για να το ανοίξετε, θα πρέπει να εκτελέσετε το πρόγραμμα επεξεργασίας της επιλογής σας (σας προτείνω το Notepad) με δικαιώματα διαχειριστή (πριν κάνετε κλικ για να το ανοίξετε, κάντε πάνω του δεξί κλικ, και επιλέξτε “Εκτέλεση ως διαχειριστής”).

Σημείωση: Μην ανοίξετε το αρχείο αυτό με κάποιο επεξεργαστή κειμένου, γιατί μπορεί να αποθηκεύσετε από αμέλεια πληροφορίες που δεν επιτρέπονται στο συγκεκριμένο αρχείο.

Όταν ανοίξει το πρόγραμμα της επιλογής σας, κάντε άνοιγμα αρχείου, πλοηγηθείτε στον φάκελο που σας έχω υποδείξει παραπάνω, και στο όνομα αρχείου γράψτε “hosts” (μαζί με τα εισαγωγικά) και πατήστε άνοιγμα.

Όταν ανοίξει το αρχείο, προσθέστε το τέλος του αρχείο μια νέα γραμμή και κάντε μια εγγραφή σαν αυτή που ακολουθεί:     

H IP που έχω γράψει είναι τυχαία. Στην δική σας περίπτωση, θα πρέπει να γράψετε την στατική IP που ορίσατε στο PC στο προηγούμενο βήμα.

Σημείωση: Αν βάλετε μια δίεση μπροστά από την IP αυτόματα μετατρέπετε το υπόλοιπο της γραμμής σε σχόλιο. Αυτό έχει ως αποτέλεσμα να “απενεργοποιήσετε” αυτή την έγγραφή από το hosts αρχείο.

Σημείωση: Αν έχετε σκοπό να χρησιμοποιήστε καταλήξεις στα domain σας που αντιστοιχούν σε πραγματικά TLD, τότε βεβαιωθείτε πως τα doman αυτά δεν είναι ήδη κατοχυρωμένα, γιατί με αυτή την τεχνική, δεν θα μπορείτε να προσπελάσετε τα πραγματικά site στο διαδίκτυο. Έτσι για παράδειγμα, αν υποθέσουμε πως θέλετε να φτιάξετε μια εγγραφή που το domain θα είναι, τότε θα πρέπει να γνωρίζεται πως δεν θα μπορείτε πλέον να προσπελάσετε αυτό το site ξανά, για όσο καιρό θα υπάρχει αυτή η εγγραφή στο hosts αρχείο σας.

Δυναμικοί VirtualHosts με XAMPP και Apache

Τέλος, σε αυτή την ενότητα θα ρυθμίσουμε τον Apache ώστε να μπορεί να δημιουργεί αυτόματα τους VirtualHosts.

Για να καταφέρουμε αυτή την ενέργεια θα πρέπει να πλοηγηθούμε στον φάκελο που είναι εγκατεστημένος ο Apache Web Server και να ανοίξουμε τον φάκελο /conf/extra/. Σε αυτό το φάκελο υπάρχει ένα αρχείο με όνομα httpd-vhosts.conf.

Σημείωση: Πριν κάνετε οτιδήποτε σε αυτό το αρχείο, κρατήστε αντίγραφο του αρχείου.

Το αρχείο αυτό θα πρέπει να έχει τον ακόλουθο κώδικα ο οποίος βέβαια αποτελεί παράδειγμα για να δημιουργήσετε τους δικούς σας VirtualHosts με XAMPP και Apache.

# Virtual Hosts
# If you want to maintain multiple domains/hostnames on your
# machine you can setup VirtualHost containers for them. Most configurations
# use only name-based virtual hosts so the server doesn't need to worry about
# IP addresses. This is indicated by the asterisks in the directives below.
# Please see the documentation at
# <URL:>
# for further details before you try to setup virtual hosts.
# You may use the command line option '-S' to verify your virtual host
# configuration.
# Use name-based virtual hosting.
##NameVirtualHost *:80
# VirtualHost example:
# Almost any Apache directive may go into a VirtualHost container.
# The first VirtualHost section is used for all requests that do not
# match a ServerName or ServerAlias in any  block.
##<VirtualHost *:80>
    ##ServerAdmin postmaster@dummy-host.localhost
    ##DocumentRoot "C:/Web Server/xampp/htdocs/dummy-host.localhost"
    ##ServerName dummy-host.localhost
    ##ServerAlias www.dummy-host.localhost
    ##ErrorLog "logs/dummy-host.localhost-error.log"
    ##CustomLog "logs/dummy-host.localhost-accesss.log" combined
##<VirtualHost *:80>
    ##ServerAdmin postmaster@dummy-host2.localhost
    ##DocumentRoot "C:/Web Server/xampp/htdocs/dummy-host2.localhost"
    ##ServerName dummy-host2.localhost
    ##ServerAlias www.dummy-host2.localhost
    ##ErrorLog "logs/dummy-host2.localhost-error.log"
    ##CustomLog "logs/dummy-host2.localhost-accesss.log" combined

Σημείωση: Και σε αυτή την περίπτωση, σε κάθε γραμμή που τοποθετείτε μια δίεση στην αρχή της, μετατρέπετε αυτόματα όλη την γραμμή σε σχόλιο, με αποτέλεσμα ο Apache Web Server να την αγνοεί πλήρως.

Εμείς τώρα, για να δημιουργήσουμε τους δικούς μας δυναμικούς VirtualHosts, θα προσθέσουμε στο τέλος του αρχείο των ακόλουθο κώδικα:

UseCanonicalName Off
    VirtualDocumentRoot "C:/Web Projects/%3/%2.1/%2+"
    DirectoryIndex  index.php index.html
    <Directory "C:/Web Projects/*/*/*">
        Options FollowSymLinks
        AllowOverride All
        Allow from all

Σημείωση: Προσέξτε πως όταν αναφέρομαι σε διαδρομές στο σύστημα αρχείων των Windows μέσα στα αρχεία ρυθμίσεων του Apache δεν χρησιμοποιώ κανονικά slash, αλλά ανάποδα (το σύμβολο της διαίρεσης), και επίσης χρησιμοποιώ εισαγωγικά.

Επεξήγηση του κώδικα

UseCanonicalName Off

Αποτρέπει τον Apache να δημιουργήσει ένα URL που να στοχεύει στον εαυτό του.


Μέσα σε αυτές τις “εντολές” ορίζουμε τον δυναμικό VirtualHost. Στην πρώτη γραμμή θα πρέπει να αντικαταστήσετε την IP με την στατική IP που έχετε ορίσει στον υπολογιστή σας από το βήμα που περιγράψαμε παραπάνω. Ο αριθμός 80 υποδηλώνει την θύρα στην οποία ακούει αυτός ο VirtualHost και που στην προκειμένη περίπτωση είναι η θύρα http.

VirtualDocumentRoot "C:/Web Projects/%3/%2.1/%2+"

Με αυτή την “εντολή” λέμε στον Apache πως να εντοπίσει αυτόματα ένα Project μέσα στο σύστημα αρχείων και να το επιστρέψει στον χρήστη, βάση του domain που έχει εισάγει ο χρήστης.

Ποιο συγκεκριμένα. Στην δική μου περίπτωση, έχω δημιουργήσει την ακόλουθη δομή φακέλων για τα έργα μου:

    Web Projects\

Και έτσι με την VirtualDocumentRoot λέω στον Apache. Θα βρεις το project που σου ζητάει ο χρήστης στον φάκελο C:\Web Projects\%3 (είναι το TLD μου [ext])\%2.1 (θα πάρει το πρώτο γράμμα του domain)\%2+ (θα πάρεις όλο το domain)\

Έτσι, αν για παράδειγμα ο χρήστης ζητήσει το domain ο Apache θα κάνει τα ακόλουθα βήματα:

  • Θα αποδομήσει το url που του ζήτησαν και θα θέσεις στην “μεταβλητή” %1 το www, στην “μεταβλητή” %2 το business-domain και στην “μεταβλητή” %3 το ext
  • Στη συνέχεια θα αρχίσει να δομεί τη διαδρομή που είναι τα αρχεία του έργου αρχίζοντας από τον φάκελο που γνωρίζει και είναι ο C:\Web Projects\
  • Επόμενο βήμα είναι να πάρει και να βάλει στην διαδρομή την “μεταβλητή” %3, οπότε η διαδρομή πλέον είναι C:\Web Projects\ext\
  • Επόμενο βήμα είναι να πάρει από την μεταβλητή %2 τον πρώτο χαρακτήρα με την χρήση της μεταβλητής %2.1 και έτσι η διαδρομή πλέον γίνετε C:\Web Projects\ext\b\
  • Τέλος, θα πρέπει από να τοποθετήσει στο τέλος της διαδρομής την “μεταβλητή” %2 και οτιδήποτε είναι δεξιά από αυτή με την “μεταβλητά” %2+, και έτσι η διαδρομή πλέον γίνετε C:\Web Projects\ext\b\business-domain.ext\

Σημείωση: οι αριθμοί %1, %2, %3 δεν είναι μεταβλητές, αλλά τις αναφέρω ως μεταβλητές για να γίνουν ποιο κατανοητές από αρχάριους χρήστες.

Σημείωση: ο Apache είναι αρκετά ευέλικτος σε ότι αφορά την δομή που θα ορίσετε στο σύστημα αρχείων σας, και ο περιορισμός είναι καθαρά η φαντασία σας. Αν θέλετε, μπορείτε να δείτε εδώ όλες τις δυνατότητες της VirtualDocumentRoot.

Σημείωση: Η μορφή που θα δώσετε στο domain σας, εξαρτάτε από εσάς, και την ορίζετε κατά την δημιουργία του στο αρχείο hosts που αναφέραμε παραπάνω. Το μόνο που πρέπει να προσέξετε είναι να συμβαδίζει η δομή του domain που δείτε, με την δομή του συστήματος αρχείων στον υπολογιστή σας.

DirectoryIndex  index.php index.html

Αυτή η εντολή, λέει στον Apache, πως σε κάθε έργο, όταν θα υπάρχει το αρχείο index.php ή το αρχείο index.html θα το φορτώνει αυτόματα όταν δεν υπάρχει κάποιο αρχείο στο URL. Για παράδειγμα όταν κάποιος θα επισκεφτεί το URL το αρχείο που θα φορτωθεί θα είναι το index.php ή αν δεν υπάρχει αυτό, και υπάρχει το index.html, διαφορετικά θα εμφανίσει τα περιεχόμενα του καταλόγου.

<Directory "C:/Web Projects/*/*/*">

Με αυτή την εντολή ορίζουμε τους κανόνες που θα ισχύουν σε όλους τους φακέλους κάτω από τον φάκελο C:/Web Projects/,

Options FollowSymLinks

Με αυτή την εντολή λέμε στον Apache ότι του επιτρέπουμε να ακολουθεί συντομεύσεις αρχείων που υπάρχουν στους καταλόγους των έργων μας.

AllowOverride All

Με αυτή την εντολή λέμε στον Apache πως μπορούμε να μεταβάλουμε τις ρυθμίσεις του μέσα από τους φακέλους των έργων μας με την χρήση του αρχείου .htaccess

Allow from all

Τέλος με αυτή την εντολή του λέμε ότι η προσπέλαση των έργων μας μπορεί να πραγματοποιηθεί από όλους.

Σημείωση: Μην σας τρομάζει αυτή η εντολή. Κανένας από τον έξω κόσμο δεν θα έχει πρόσβαση στον υπολογιστή σας για όσο ακολουθείτε τους κανόνες ασφαλείας που είναι πιθανότατα ήδη ενεργοποιημένοι για εσάς.

Ολοκλήρωση της διαδικασίας

Αφού κάνετε τις ρυθμίσεις σας στο αρχείο httpd-vhosts.conf, αποθηκεύστε το. Στη συνέχεια θα πρέπει να βεβαιωθούμε πως ο Apache γνωρίζει ότι πρέπει να χρησιμοποιήσει αυτό το αρχείο.

Για να βεβαιωθούμε, θα πρέπει να ανοίξουμε το αρχείο ρυθμίσεων του Apache που είναι στον φάκελο conf του Apache Web Server.

Το αρχείο που θέλουμε είναι το httpd.conf.

Σημείωση: Πριν κάνετε οποιαδήποτε αλλαγή σε αυτό το αρχείο, δημιουργήστε ένα αντίγραφο ασφαλείας του αρχείου.

Ανοίξτε το httpd.conf και προσπαθήστε να εντοπίσετε την γραμμή “Include conf/extra/httpd-vhosts.conf

Αν αυτή η γραμμή έχει μπροστά της μια δίεση, τότε αφαιρέστε την δίεση και αποθηκεύστε το αρχείο.

Σε αυτό το σημείο θα πρέπει να κάνετε επανεκκίνηση τον Apache Web Server.

Σημείωση: Αν για κάποιο λόγο δεν γίνετε επανεκκίνηση του Apache, τότε, πιθανότατα έχετε κάνει κάποιο συντακτικό λάθος στις ρυθμίσεις σας.

Χρήση του συστήματος

Αν έχετε ακολουθήσει σωστά όλα τα παραπάνω βήματα, τώρα θα πρέπει να είστε σε θέση να δημιουργήσετε νέα Projects που έχουν τα δικά τους domains.

Σε αυτή την κατάσταση του server σας, όταν θα θέλετε να προσθέσετε ένα νέο έργο, τα μόνα βήματα που θα πρέπει να κάνετε θα είναι η δημιουργία μιας νέας εγγραφής στο αρχείο hosts με την ίδια IP που έχετε ορίσει ως στατική στον υπολογιστή σας, και το domain του έργου.

Τέλος, ανάλογα με τις ρυθμίσεις που έχετε κάνει στο VirtualDocumentRoot θα πρέπει να δημιουργήσετε και την κατάλληλη υποδομή σε φακέλους, και το έργο σας είναι έτοιμο προς χρήση.


Είναι προφανές πως η ρύθμιση των VirtualHosts με XAMPP και Apache είναι μια δύσκολη και επίπονη διαδικασία όταν δεν γνωρίζεις ποια είναι τα απαραίτητα βήματα που πρέπει να ακολουθήσεις.

Το καλό όμως, είναι πως τελικά έχεις ένα πλήρες λειτουργικό σύστημα που σε διευκολύνει στην παραγωγή και δεν σου δημιουργεί εμπόδια.