Guide

Further categorizing your wordpress post!

Tags grouping / categorizing tags

During publishing articles, you may think that using “tags” seems too general. Many times you need more categorized tags, or grouping tags. That way, you can make user easier to find similar tags that consists in the category.

For example: You are publishing an “omelette” recipe post. You need to tag them with ingredients (egg, vegetable oil), utensils (stove, frying pan, spatula) and cooking technique (frying). That way, rather than having bunch of unsorted tags like: egg, vegetable oil, stove, frying pan, spatula, frying; you can sort them better. The example will be shown in the following figure:

Wordpress categorized tag

Fig. 1. WordPress categorized tag

Note: thanks to http://www.epicurious.com/recipes/food/views/classic-omelette-15068 for the recipe.

Moreover, if you do some tweaks in your themes template or via plugin, you can display the categorized tags in tidy manner. It’ll be useful when user wants to browse the category itself. The following picture show an example of categorized tags based on omelette recipe:

Wordpress categorized tag lists

Fig. 2. Categorized tag list

Other useful case is when you are writing a post about notebook, where you can further grouping tags to specify OS, RAM size, HDD size, VGA type, VGA size, etc. So further categorizing tags will be very useful generally.

Tag categorizing is referred by wordpress as “Taxonomy“. However even though fully supported by wordpress, it’s not easy to administrate taxonomy. I suspect that the first intent the taxonomy is developed, it is to be used as specialized themes rather than user customizable. However, with helps from plugins you can easily administrate them.

Plugins required

Types plugin

Types plugin – https://wordpress.org/plugins/types/, is a nice plugin that give you good administrator tools over post types, custom fields and custom taxonomy. Both custom fields and post types are also useful to writing posts, but right now for me the custom taxonomy is the one I need. Here is the example of custom taxonomy page provided by Types plugin:

Wordpress Types plugin custom taxonomies

Fig. 3. Types plugin custom taxonomies page

The administration is rather straightforward here. You only need to create the custom category (ingredient, utensils, cooking technique) then thanks to support of wordpress, all of them will be available in post by itself. The following figures will show how custom taxonomies will show during writing post:

Wordpress custom taxonomy on writing post

Fig. 4. Custom taxonomy on post

As you can see from the Fig. 4 above, in Post menu there are new menu items, each for custom taxonomies defined by user. And during writing post, new box below category will appear where you can fill the custom taxonomies information for the page.

Add actions and filters

Add actions and filters plugin – https://wordpress.org/plugins/add-actions-and-filters/– is a plugin which allow you to add “action hooks” and functions into your wordpress site. Types plugin already help you to maintain custom taxonomies. However, it won’t help you to display the custom taxonomies associated with the post, as shown at Fig. 1. In this case, I use this plugin to show the categorized tag / taxonomies associated with post. I use the following code snippet:

function render_taxonomy($content) {
    $excluded_taxonomies = array(
        'category',
        'post_tag',
        'nav_menu',
        'link_category',
        'post_format'
    );
    $taxonomies = get_taxonomies();
    $post_id = get_the_ID();
    $result = '';

    $result .= '<div class="post_taxonomy">';
    
    foreach($taxonomies as $taxonomy){
        if(in_array($taxonomy, $excluded_taxonomies) == false)
        {
            $obj_taxonomy = get_taxonomy($taxonomy);
            $result .= get_the_term_list($post_id , $taxonomy, '<strong>' . $obj_taxonomy->label . ': </strong>', ', ');
            $result .= '<br/>';
        }
    }
    $result .= '</div>';
    return $content . $result;
}

add_action('the_content','render_taxonomy');

That’s it. With those 2 plugins, your wordpress now has categorized tags.

Showing list of taxonomies

Now that you may want to display the list of taxonomies in one page, as shown under Fig. 2. In this case, I use the following code snippet inside “add actions and filters plugin” to add shortcode. The defined shortcode will render the list of taxonomies defined in your wordpress site. Then, the shortcode can be used in any page / post to instantly change the page / post into taxonomies list.

function render_taxonomies() {
    $excluded_taxonomies = array(
        'nav_menu',
        'link_category',
        'post_format'
    );
    $taxonomies = get_taxonomies();
    
    $result = '';
    $result .= '<div class="taxonomies">';
    
    foreach($taxonomies as $taxonomy){
        if(in_array($taxonomy, $excluded_taxonomies) == false)
        {
            $obj_taxonomy = get_taxonomy($taxonomy);
            $taxonomy_name = $obj_taxonomy->name == 'post_tag' ? 'tag' : $obj_taxonomy->name;
            $result .= '<h2><a name="' . $taxonomy_name . '">' . $obj_taxonomy->label . '</a></h2>';
            
            $query_taxonomies = array( $taxonomy );

            $args = array(
                'orderby'           => 'name', 
                'order'             => 'ASC',
                'hide_empty'        => true, 
                'exclude'           => array(), 
                'exclude_tree'      => array(), 
                'include'           => array(),
                'number'            => '', 
                'fields'            => 'all', 
                'slug'              => '',
                'parent'            => '',
                'hierarchical'      => true, 
                'child_of'          => 0,
                'childless'         => false,
                'get'               => '', 
                'name__like'        => '',
                'description__like' => '',
                'pad_counts'        => false, 
                'offset'            => '', 
                'search'            => '', 
                'cache_domain'      => 'core'
            ); 

            $terms = get_terms($query_taxonomies, $args);
            
            $result .= '<div class="taxonomy"><ul>';
            foreach($terms as $term){
                $result .= '<li>';
                $result .= '<a href="' . get_site_url() . '/' . $taxonomy_name . '/' . $term->name . '">' . $term->name . '</a>';
                $result .= '</li>';
            }
            $result .= '</ul></div>';
        }
    }
    $result .= '</div>';
    return $result;
}

add_shortcode('render_taxonomies', 'render_taxonomies');

Then to use it, just make a page with [render_taxonomies] as the content.

Conclusion

Further categorizing your wordpress site will enhance navigation experience for user.

Embed Asp.Net MVC views in class library dll

If you’re anything like me, you may want to define asp.net mvc views in class library, so that it can be used from anywhere. However, it’s not an easy task, regarding the MVC architecture of asp.net mvc. The view normally be placed at Views folder physically, making us unaware of possibility to embed the view and controller to shared library (dll).

Define view in library

Create the view file

You can create the view file inside library project. If you cannot find the view template from add file, you can choose text file then rename the extension as cshtml (razor) or aspx.

Set the view as embedded resource

The view file need to be set as embedded resource during compilation, so that the file can be referenced from other projects.

Set the build action into embedded resource

Set the build action into embedded resource

How to make asp.net mvc find embedded view

There is a way to tell asp.net mvc to look up from specific source. One of them is embedded view. It can also get from database but I haven’t tried that or need a case for that.

To tell the asp.net mvc to look up at embedded resource, first we need to define a VirtualFile (System.Web.Hosting.VirtualFile). VirtualFile class can act as a “false” view file. When accessed, it can read the embedded resource file and return it instead of serving the asp.net mvc engine with physical file. Next step, we need to supply asp.net mvc with VirtualPathProvider class that can direct the engine into finding and serving the VirtualFile instead of physical file. Both of the files that will make it possible to serve asp.net views from source other than physical file.

Here’s the code for both class (with supporting class):

    public class EmbeddedResourcePathConfiguration
    {
        public EmbeddedResourcePathConfiguration(string rootNameSpace, string viewFolderName, Assembly resourceAssembly)
        {
            this.RootNameSpace = rootNameSpace;
            this.ViewFolderName = viewFolderName;
            this.ResourceAssembly = resourceAssembly;
        }
        public string RootNameSpace { get; set; }
        public string ViewFolderName { get; set; }
        public Assembly ResourceAssembly { get; set; }
        public string ViewNameSpace
        {
            get
            {
                return RootNameSpace + "." + ViewFolderName;
            }
        }

    }

    public class EmbeddedResourceNameProvider
    {
        private EmbeddedResourcePathConfiguration configuration = null;
        public EmbeddedResourcePathConfiguration Configuration
        {
            get { return configuration; }
            set { configuration = value; }
        }

        public string GetResourceName(string virtualPath)
        {
            var resourcename = virtualPath
                .Substring(virtualPath.IndexOf(configuration.ViewNameSpace));

            return resourcename;
        }
    }

    public class EmbeddedVirtualFile : VirtualFile
    {
        public EmbeddedVirtualFile(string virtualPath, EmbeddedResourcePathConfiguration configuration)
            : base(virtualPath)
        {
            this.configuration = configuration;
            EmbeddedResourceNameProvider.Configuration = configuration;
        }
        private EmbeddedResourcePathConfiguration configuration = null;

        EmbeddedResourceNameProvider embeddedResourceNameProvider = new EmbeddedResourceNameProvider();
        public EmbeddedResourceNameProvider EmbeddedResourceNameProvider
        {
            get { return embeddedResourceNameProvider; }
            set { embeddedResourceNameProvider = value; }
        }

        public override Stream Open()
        {
            string resourcePath = EmbeddedResourceNameProvider.GetResourceName(VirtualPath);
            return configuration.ResourceAssembly.GetManifestResourceStream(resourcePath);
        }
    }
    public class EmbeddedViewPathProvider : VirtualPathProvider
    {
        EmbeddedResourceNameProvider embeddedResourceNameProvider = new EmbeddedResourceNameProvider();
        public EmbeddedResourceNameProvider EmbeddedResourceNameProvider
        {
            get { return embeddedResourceNameProvider; }
            set { embeddedResourceNameProvider = value; }
        }

        private EmbeddedResourcePathConfiguration configuration = null;
        public EmbeddedViewPathProvider(EmbeddedResourcePathConfiguration configuration)
        {
            this.EmbeddedResourceNameProvider.Configuration = configuration;
            this.configuration = configuration;
        }

        private bool IsVirtualFile(string virtualPath)
        {
            return virtualPath.Contains(configuration.ViewNameSpace);
        }

        private bool ResourceFileExists(string virtualPath)
        {
            var resourcename = EmbeddedResourceNameProvider.GetResourceName(virtualPath);
            var result = resourcename != null && configuration.ResourceAssembly.GetManifestResourceNames().Contains(resourcename);
            return result;
        }

        public override System.Web.Caching.CacheDependency GetCacheDependency(string virtualPath, System.Collections.IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            if (IsVirtualFile(virtualPath))
            {
                return new System.Web.Caching.CacheDependency(configuration.ResourceAssembly.Location);
            }
            return base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }

        public override bool FileExists(string virtualPath)
        {
            if (IsVirtualFile(virtualPath))
            {
                bool exists = ResourceFileExists(virtualPath);
                return exists;
            }
            else
            {
                return base.FileExists(virtualPath);
            }
        }

        public override VirtualFile GetFile(string virtualPath)
        {
            if (IsVirtualFile(virtualPath))
            {
                return new EmbeddedVirtualFile(virtualPath, configuration);
            }
            else
            {
                return base.GetFile(virtualPath);
            }
        }
    }

Register the path provider into applications

The last step is to register the path provider to application. You can use the following code at global.asax, inside Application_Start.

EmbeddedResourcePathConfiguration configuration =
                    new EmbeddedResourcePathConfiguration(
                        rootNameSpace: "HtmlViewTemplate",
                        viewFolderName: "Views",
                        resourceAssembly: Assembly.Load("HtmlViewTemplate"));
                HostingEnvironment.RegisterVirtualPathProvider(new EmbeddedViewPathProvider(configuration));