WordPress Posts/Blogs Filter with Search and Category Select/Dropdown, No Plugins

Take a look at the example inside the box below.

  1. We have a search box.
  2. We have category select box.
  3. We have a list of posts.
  4. We have a “load more” button.
  5. When we type anything on the search box it automatically filters the listed posts.
  6. If we select anything on the category, it filters the posts by category.
  7. Dynamically, the search box and the category select box work together. If we select a category, and type in keywords, it will only search and filter the post lists under that category.

Demo Example:


So how did I do that? It is simple, look at the code down below. Add it to your functions.php file.

// These lines of code register the 'custom_filter_posts' function to be called when an AJAX request with the action 'custom_filter_posts' is received.
add_action('wp_ajax_custom_filter_posts', 'custom_filter_posts');
add_action('wp_ajax_nopriv_custom_filter_posts', 'custom_filter_posts');

function custom_filter_posts() {
    // These lines retrieve the keyword, category, page number, and posts per page values from the AJAX request's parameters. If any of these parameters are not provided, they default to empty string, 1, and the default number of posts per page respectively.
    $keyword = isset($_GET['keyword']) ? $_GET['keyword'] : '';
    $category = isset($_GET['category']) ? $_GET['category'] : '';
    $page = isset($_GET['page']) ? $_GET['page'] : 1;
    $posts_per_page = isset($_GET['posts_per_page']) ? $_GET['posts_per_page'] : get_option('posts_per_page');

    // These lines construct arguments for the WP_Query object which will be used to fetch posts from the database.
    $args = array(
        'post_type' => array('post'), // Include both posts and pages
        'posts_per_page' => $posts_per_page, // Number of posts to display per page
        'paged' => $page, // Current page number
        's' => $keyword, // Search keyword
    );

    // Add category filter if a category is selected
    if (!empty($category)) {
        $args['tax_query'] = array(
            array(
                'taxonomy' => 'category', // Taxonomy to filter (in this case, category)
                'field'    => 'term_id', // Use term ID to filter
                'terms'    => $category, // The selected category ID
            ),
        );
    }

    // Perform the query to retrieve posts based on the provided arguments.
    $query = new WP_Query($args);

    // Check if posts were found
    if ($query->have_posts()) :
        // Loop through each post in the query result
        while ($query->have_posts()) : $query->the_post();
            // Display each post's title and excerpt
            echo '<div class="search-result">';
            echo '<h3><a href="' . get_permalink() . '">' . get_the_title() . '</a></h3>';
            echo '<small>' . get_the_excerpt() . '</small>';
            echo '</div>';
        endwhile;
    else :
        // If no posts were found, display 'No more posts'
        echo 'No more posts';
    endif;

    // Reset post data to ensure that global variables are restored to their original state after the query
    wp_reset_postdata();

    // Terminate the script execution
    die();
}



// Register shortcode
function custom_search_shortcode() {
    ob_start(); // Start output buffering
    ?>
    <div style="border: 2px solid #000; padding: 30px; ">
        <form role="search" method="get" class="search-form" id="custom-search-form" action="<?php echo esc_url( home_url( '/' ) ); ?>">
            <label>
                <span class="screen-reader-text"><?php echo _x( 'Search for:', 'label' ); ?></span>
                <input type="search" class="search-field" placeholder="<?php echo esc_attr_x( 'Search …', 'placeholder' ); ?>" value="<?php echo get_search_query(); ?>" name="s" id="search-keyword"/>
            </label>

            <label>
                <?php
                $categories = get_categories();
                if ( $categories ) {
                    echo '<select name="category" id="search-category">';
                    echo '<option value="">Select Category</option>';
                    foreach ( $categories as $category ) {
                        echo '<option value="' . $category->term_id . '">' . $category->name . '</option>';
                    }
                    echo '</select>';
                }
                ?>
            </label>
        </form>
        <br />
    
        <div id="search-results"></div>
    	<button id="load-more-btn">Load More</button>
    </div>
    

    <script>
    jQuery(document).ready(function($) {
        var postsPerPage = 3; // Number of posts to load initially
        var currentPage = 1; // Current page
        var keyword = $('#search-keyword').val();
        var category = $('#search-category').val();

        // Function to load posts
        function loadPosts() {
            $.ajax({
                type: 'GET',
                url: '<?php echo esc_url( admin_url('admin-ajax.php') ); ?>',
                data: {
                    action: 'custom_filter_posts',
                    keyword: keyword,
                    category: category,
                    page: currentPage,
                    posts_per_page: postsPerPage
                },
                success: function(response) {
                    $('#search-results').append(response);
                }
            });
        }

        // Load initial posts
        loadPosts();

        // Load more posts when the button is clicked
        $('#load-more-btn').on('click', function() {
            currentPage++; // Increment current page
            loadPosts(); // Load more posts
        });

        // Trigger search when the keyword input changes
        $('#search-keyword').on('input', function() {
            keyword = $(this).val(); // Update keyword
            currentPage = 1; // Reset current page
            $('#search-results').empty(); // Clear existing results
            loadPosts(); // Load posts with updated keyword
        });

        // Trigger search when the category dropdown changes
        $('#search-category').on('change', function() {
            category = $(this).val(); // Update category
            currentPage = 1; // Reset current page
            $('#search-results').empty(); // Clear existing results
            loadPosts(); // Load posts with updated category
        });
    });
    </script>

    <?php
    return ob_get_clean(); // Return the buffered content and clean the buffer
}
add_shortcode('custom_search', 'custom_search_shortcode'); // Register the shortcode

Then on your page, add this shortcode [ custom_search ]

If you are familliar with PHP and WordPress, just read through the code comments and try to understand.

Bootstrap Tagsinput – Manually adding class on loop-added tags

Bootstrap Tagsinput plugin is awesome. It has great functionality and lots of methods and functionalities it can offer. For more info about it, visit https://bootstrap-tagsinput.github.io/bootstrap-tagsinput/examples/

Let’s say you have this code.

<p><label for="npis">10 digit numbers</label><br />
<input type="text" id="num" name="npis" data-role="tagsinput" /><br />
<span class="v_error"> </span>
</p>

To initialize the Tagsinput plugin.

jQuery('input#num').tagsinput({
    tagClass: 'badge badge-default',
    maxChars: 10,
    trimValue: true,
});

Now, you want to check the input first before adding them as tags, let’s say numbers only and it should be 10 digit numbers separated by commas.

// event before add tag
jQuery('input').on('beforeItemAdd', function(event) {
    // event.item: contains the item
    // event.cancel: set to true to prevent the item getting added

    // check item if numbers only using regex
    var isNum = /^\d+$/.test(event.item);
    if(!isNum){
        jQuery('span.v_error').html("Enter multiple numbers separated by commas (e.g., 1234567890, 4567891231)");
        event.cancel = true;
    } else if(event.item.length !== 10){ // check if length of input is 10
        jQuery('span.v_error').html("Your numbers should be a 10-digit number.");
        event.cancel = true;
    } else {
        jQuery('span.v_error').html('');
    }
});

Now, what happens here is that, when you type in the keyboard, before the tags are created, it will detect first if there are letters or special characters in the input, if there are none and if the number input is equal to 10 digits, then the tag is created. Check the image below.

Bootstrap Tagsinput – Manually adding class on loop-added tags

Now the problem, you want to submit these numbers to an API, then the API checks what numbers are valid or not. Let us say, NPI numbers for doctors. Each doctor has a 10-digit NPI number. So the API checks in the server database which ones are valid or not, then responds back to the website browser which ones are valid/correct or invalid/incorrect. Now we want to display it to the user by highlighting the color, valid numbers are purple/lavender, just like the image above, and invalid NPIs are orange. Also you want to be able to still type in numbers in the input to resubmit.  In our case, by default, when a tag is created, I set the color to purple/lavender.

Here’s the solution.

First we need to create an empty array, this is where we will store the list of invalid numbers.

Check if there are invalid numbers by checking the length of the returned data array, then we iterate from there.

Then we use the add method from Tags Input to add the tags to the input box.

Then we push the invalid numbers to the empty array.

// create an empty array
let invalid_numbers = [];
// If number doesnt exist
// array_of_invalid_numbers will be an array of invalid numbers returned from the API
if(result_from_api.array_of_invalid_numbers.length){
    for (let i = 0; i <= result_from_api.array_of_invalid_numbers.length - 1; i++){
        // this is the Tagsinput method to add tags
        jQuery('input#num').tagsinput('add', result_from_api.array_of_invalid_numbers[i]);

        // we push the invalid numbers to the empty array invalid_numbers
        invalid_numbers.push(result_from_api.array_of_invalid_numbers[i]);
    }

    jQuery('span.invalid_error').html("Some numbers were not found in our database. Please remove or correct the numbers highlighted in orange.");
} else {
    jQuery('span.invalid_error').html('');
}

Then we get all tags added from the input box.

Then we loop through it using the jQuery function $.each().

Then we compare it to the invalid_numbers array.

Then remove or add classes.

// we get all tags by their class
// then we loop using the .each() function
// then we compare it to the invalid_numbers array
// if it matches then we remove the "badge-default" class and repalce it with "badge-invalid"
for(let inva_num = 0; inva_num < invalid_numbers.length; inva_num++){
    // this is the class generated to the tag inputs elements, check it in your browser console
    jQuery('.bootstrap-tagsinput span.tag').each(function(){
        if(jQuery(this).text() == invalid_numbers[inva_num])
        {
            jQuery(this).removeClass( "badge-default" ).addClass( "badge-invalid" );
        }
    });
}

The final result will be like this.

The orange ones are the invalid, and the purple one is the valid.

Why Saving Money is So Damn Hard

How much percentage do you save with your monthly income? 50% 70% 30%.

Most people save at least 20%, that is a good percentage for savings. While you spend 80% for things such as food, rent, mortgages(if you have mortgages, your savings can be lesser as mortgages tend to be higher cost) etc.

But sometimes you overspend. You overspend of food, on a date, on items and on many things.

For now I’m sure you know the difference between wants and needs. It’s basic. Basically, wants are things that you don’t need. You can survive without the “wants”. While needs are important. You need the need things in order to survive in your life and help you in your daily living, education and career. A high end expensive PC is not a want for video editors or game developers, it is a need. They need it for their career. While buying an expensive PC for gaming is first a need, and then a want. I don’t bash people for playing games, yes you need a high end PC for heavy gaming, but do you need to play games in life or is it just a want?

Overspending is the enemy of saving. We need to find the root cause of overspending, here it is, it’s very simple.

  1. You think you have enough money in your bank atm card.
    This is the most important thing to think about. When you have money in your atm card or wallet, you don’t worry about anything. You become careless. You purchase “WANTS” and not “NEEDS” You can buy an expensive dinner, or buy an item that amazes you without any worry in the world.You think “as long as I can retain that amount of money in my bank I can do what I want”.This is a problem. Many people are like this. Smart people do not leave money in their banks, they invest it. For them, it is better to use the money to buy an item that is a need rather than a money stuck in the bank.

    Money is meant to be circulated, not to be saved. This statement kind-of goes against the title of this article. But let me explain further.

  2. You don’t plan.
    This is is connected to #1.Simple. if you have plans in the future, then you’re a smart person. You save money for your plans. Whether this plans are buying need items or travelling, it’s good to have plans.Having money stuck in your bank plus you don’t have plans, equals disaster. When you plan, you plan it seriously. Whether you’re out for a walk, or a dinner date, your plans are stuck in your head. You are mindful of your expenses because all your money are saved for your plans. You wanna buy a car? buy a new laptop? It’s better to have a plan, this helps you save money for your goals.

    So next time you spend money for that expensive dinner? Stop. Stop being a mindless fool. Save money and spend it on your goals.

Real life experience.

One time I had 100,000 in my bank. Apparently, it retained for more than a year. It never went up. Sometimes I buy an item worth 10k, with 90k remaining. The next payday, its’ back to 100,000-ish. That’s one of my stupidest, lowliest, dumbest era of my life. I never saved money, I never had plans, I never spent that 100,000 for something good. I just went foolishly spending on things I want and never increased it. When you have money in the bank, and a relative or a close family member asks for money, you tend to give more. And families don’t repay. You could give away money because you think “because I have money” when in fact you’re slowly making yourself poor.

Then one day, I decided to buy a 100,000 worth PC. It is for my game development career. Then I realized suddenly it changed me. I suddenly became aware of my spending. All the useless expenses in my mind I suddenly regret or suddenly I didn’t want them anymore.

I became mindful suddenly. Before planning, I was thinking inviting my partner to a dinner, go out, grab some starbucks coffee, spend a minimum 1,000 in one day just for dinner. But after planning, I suddenly didn’t want to do that. See my point?

TIP

So for my tip, when you go out alone or on a date, remember your goals and plans, and make them a priority. think about it before going into a restaurants. This is also helpful when you’re stopped outside and is trapped by sales people, making you buy stuff you don’t really need. Better, when you’re trapped by scammers, and is trying to force you to purchase their stuff, just remember that you have a plan, a goal a priority, this will help you turn them down, say no. You will become a strong tower that cannot be torn down. When you’re outside, remember how much money you have in your bank, it can be a third, or half of the price of the thing you need to buy. Every cent counts.

The Information Age, why you should realize that everybody struggles, just like you

In this day and age, we are in the information age, you can access information so easily, you can become a “somewhat expert” in something or just about anything. That is a good thing, a very good thing. The information age has many benefits, but it also has many downsides. The most basic disadvantage is privacy. Your info can be accessed all around the web, it can be used to take advantage of you, your privacy, and all. But what I realized is something more subjective, something that I know is affecting most people.

In the information age, knowledge and information are everywhere, our brains should also try to gather all this information to survive in society.

In innovating careers and fields, information and knowledge are being shared around the world every day, creating more innovative data, creating more new studies, creating new information, creating new things to learn. To survive, we need to keep adapting to these ever-accelerating fast changes.

In the web development career, let’s say you just finished learning Laravel framework, or React JS framework, then suddenly a new JS Library pops out, Three JS. Now you will need to learn concepts of 3D objects, faces, vertices, and the never-ending bucket of information.

You become frustrated. 

You see a lot of people seem to adapt quickly, you feel like a loser.

NO!

Everyone struggles just like you, even the smartest ones feel the same way as you. In the information age, a lot of people struggle with studying, memorizing, remembering information. To survive at this age, all you need is perseverance. This may sound corny, you may have heard this a lot in self-improvement seminars. Well, it’s the truth. That’s why the numbers of successful people are lower than the least successful people. The rich are fewer, while the poor are in the billions in number. The rich perseveres, the poor want an easy life.

Use technology against technology.

With the wave of information, use your computer for the overwhelming data. You don’t need to memorize everything, save it on your computer. What is important is the theory, the concept of the data, the information you are learning.

This was my mistake, applying to an IT company, I always think “I need to know this and that.”. You will only burn yourself out. Try to learn the basic concept, the general structure, the whole picture. Just save and ready the smaller and countless info in your computer, your phone, your flash drives. LOL

Investing in One’s Self?

Wealth is such a good thing, it’s not just about money and assets, it’s also about your well being as a whole. Your mind, your soul, your health, and your life is in the scope of wealth.

When we hear the word “invest”, “investing”, “investment”, what usually comes to mind is about money, business and assets. That is true, but investment is also about providing and endowing something on someone or something or on yourself.

When we study in our schools we are investing knowledge in our selves. At the same time, we are teaching ourselves the value and virtue of responsibility as students. I believe what we put into something, it multiplies. Well there are things that when we put, it doesn’t multiply or increase.

There’s a story in the Bible about the Parable of the Talents in Matthew 25, the master gave talents to his servants. Two servants worked on the talents they were given and it doubled. One servant dug a hole in the ground and buried the talent so it wont get lost. When the master returned, he was pleased with the two servants and rewarded them while he was angry with the one servant who buried the talent in the ground, he was punished and all his talent was taken way from him.

It’s a story full of truth and wisdom. We can learn a lot from that parable.

In life we all live in different environments and arrangements, some of us live in first world countries, some in third world, some were born rich, and some poor, some were given education while some had no chance to go to school. Our scenarios in life are all different. But we can all be wealthy and prosperous, all we need to do is “invest”.

Invest your time for self improvement, invest your self in becoming a better person than yesterday. Wherever we are, whatever our situation is, these are all opportunities, these are all given, we need to use it.

Awhile ago I was playing games, just sitting lazy with my subconscious mind then the conscious mind snapped me back. What the hell am I doing? I decided to stand up, do house chores, started my laundry while thinking what new technology should I learn and master?

Also I was vaping, I thought, if I invest in myself, I should also invest in my health, I decided to throw my vapes into the trash. No more smoking for me.

Even your posture, if you don’t fix your posture you’re limiting yourself for a better future. A good posture can make you taller, more beautiful/handsome. You will look more healthy, people will admire you, people will respect you, you become more agreeable, it’s beneficial for making deals with clients and businesses, and your future body health will thank you for it.

Look at the things that multiply, and invest on it.

Why use PHP Namespace?

PHP Namespace is a virtual directory you create in PHP. It is used to avoid conflicts when declaring Classes in PHP.

In Object-Oriented Programming, it is best practice to place one class in one file, if there are 2 classes in 1 file then that just defeats the purpose of OOP. So why use Namespace? Here is an example.

In the index.php file, we have the code that:

  1. Requires 2 PHP files
  2. Instantiates the class A
require('first-class.php');
require('second-class.php');
$object = new A;

In first-class.php, we have a class and a method that displays a text.

class A{
    public function __construct(){
        echo "I am the first class A.";
    }
}

In our second file, second-class.php, we have a class with the same name.

class A{
    public function __construct(){
        echo "I am the second class A.";
    }
}

Now if we run the index.php file, we will get an error.

Fatal error: Cannot declare class A, because the name is already in use in C:\xampp\htdocs\php_tester\namespace\second_class.php on line 2

What happened is that the instance variable object is confused on which Class to instantiate. To solve this is to use namespace. This is important especially on huge projects and projects that use libraries. Namespace can also help collaborative projects for teams who code on a single project.

To use a namespace is simple. We add the namespace code at the top of the class and specify a name for it. In first-class.php file, we update the code to:

namespace FirstA;
class A{
    public function display_text(){
        echo "I am the first class A.";
    }
}

Now in our code in index.php, when we want to access the methods and properties under the first-class.php file, we update the following code to:

require('first-class.php');
require('second-class.php');
$object = new FirstA\A; //qualified class name

//result "I am the first class"

The code $object = new FirstA\A; is called the Qualified Class Name.

We can also place a namespace in our index.php file.

namespace FirstA;
require('first-class.php');
require('second-class.php');
$object = new A; //unqualified class name

//result "I am the first class"

Notice that I removed the namespace in the instantiation, we can call it as Unqualified Class Name.

But… how do we call the class under second-class.php? We do it by:

namespace FirstA;
require('first-class.php');
require('second-class.php');
$object = new A; //unqualified class name
echo "<br />"
$object = new /A; //fully qualified class name

We call it Fully Qualified Class name or FQCN.

We can also use the code “use“.

//namespace FirstA;
require('first-class.php');
require('second-class.php');

use FirstA\A as NewA

$object = new NewA; //unqualified class name
echo "<br />"
$object = new /A; //fully qualified class name

Mobile Legends’ Annoying Team Algorithm

So you are a good team player in Mobile Legends. Either you have mastered a single hero or have mastered more than 5 heroes, you are a good player with a win rate of 60% and above.

Then comes Mobile Legend’s algorithm. Mobile Legends like any other games want to control people so people get hooked up. If a game is too easy, people will get easily bored. If the game is challenging, then people will get hooked to it because they want a challenge. Mobile Legends keep people hooked up in 2 ways. They have their own algorithm so players are always hooked up and always wanting to play more and win more.

  1. The Team Algorithm
    Supposed you are a good player and a good team player, and you won 3 to 4 games in Rank Mode. The next game, the algorithm will automatically set you to a player who has lost in their 3 or 4 games in a row. Or worse, feeders, you will be teamed with feeders. The worst thing is there are more dumb players than good players. I am sure you know that.

    So, here you are a good player, with 3 or 4 dumb/feeder teammates and 1 average player. The result is, there is a high chance you will lose and lose a star.

  2. Stats Controlling Algorithm
    Have you noticed how your hero starts performing/damaging very low compared to your previous matches? I noticed it too. If you are a good player with too many wins on your last 3 or 4 games, the algorithm will lower your stats in the background. Of course, they will not display it on the stat bar but in the background, your stats are decreased.
    That’s why your damage is lower, and your enemies have higher.

Just like the algorithms in gambling, casinos want their customers hooked up so there’s always a higher chance of you losing in the casino than winning, but still people get hooked up because you know, greed. Facebook and other social media also hire people who know how to get people hooked in to their platforms, from the display, the interface and the content they display. It’s all psychological. The same with games like Mobile Legends, the feeling of winning feels so great so the game will give you higher chance to lose so you will be dissatisfied and will keep on playing just to have the win.

I am deleting my account and the game app now, I don’t want to play games that are being manipulated.

DNN Custom Editor not working – Fixed

If you are using DNN and trying to edit a text or HTML module, if there are no toolbars displayed in the editor and if the Custom Editor link doesn’t work, then there is a simple fix for that.

Go to Persona Bar > Settings > SEO > Expression Change the value of “Prevent Lowercase URL Regular Expression” with “popUp”

WordPress 5 Page Editor Will Not Let You Exit Page

WordPress 5 has finally come to the WordPress CMS. It has many features that lets it step up it’s game.

One thing I noticed while using WordPress 5 is that when you’re editing a page using it’s custom built Page Editor, if you want to go to another Admin page, it doesn’t let you. It requires you to Save/Update your current page first before it exits you.

Closing the browser doesn’t work either, nor closing the tab. It prompts you to Save the current work before you can leave.

I am sure that the WP team did not put the functionality on purpose but it’s a bug of a script or maybe the browser having some issues or conflicts. I am currently using Chrome as a browser, I don’t know if this happens on other browsers.

This is a bad thing especially when you didn’t edit a content of a page or post and you’re just visiting the page editor to copy some custom code or you’re just checking the page settings so you can make a reference for other pages. You don’t save the page, it’s a bad practice, what if you accidentally touched something or added some texts or codes or accidentally deleted a code or text.

The best way to exit the page is to force close the application, or a technique that I do, click the close button on top while pressing enter.

Specified key was too long – Migration error – Laravel

If you encounter this error when migrating database in your Laravel project, “Specified key was too long” then you might be using an older version of MySQL or MariaDB.

To fix it. Go to your App directory then Providers and open AppServiceProvider.php

Specified key was too long - Migration error - Laravel
Specified key was too long – Migration error – Laravel

Add the Schema Facad at the top “use Illuminate\Support\Facades\Schema;

Then paste this inside Boot function “Schema::defaultStringLength(191);

That’s it! Run your migration again.