Change title text – PHP, MySQL, Node JS

In this article, we are going to show you, how you can change title text of an HTML page using simple Javascript. We will show a real-time notification to your users in their title bar using PHP, MySQL, and Node JS. You can show a notification in a title bar with just PHP and MySQL. But the “real-time” effect can only be achieved with Node JS.

We can change title text using Javascript’s document.title object, but we will show you with a real-world example.

What we will do:

  1. Save notification in the database
  2. Display counter in the title bar
  3. Show all unread notifications to the user
  4. Mark notification as read
  5. Make notifications real-time

1. Save notifications in the MySQL database

First, we need to save the notifications in the database. Notifications can be of any type, for example, “a new message is received” or “your account has been activated” etc. We will create a new file named “send-notification.php“.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<?php
 
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
    // create table if not exists
    $sql = "CREATE TABLE IF NOT EXISTS notifications (
        id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
        user_id INTEGER,
        message TEXT,
        is_read BOOLEAN,
        created_at DATETIME
    )";
 
    // prepare the query
    $statement = $conn->prepare($sql);
     
    // execute the statement
    $statement->execute();
 
    // user who needs to receive the notification
    $user_id = 565; // replace this your user ID
    $message = "You have received a new message " . time() . ".";
    $is_read = 0;
 
    // insert in notifications table
    $sql = "INSERT INTO notifications (user_id, message, is_read, created_at) VALUES (?, ?, ?, NOW())";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $user_id, $message, $is_read
    ]);

Comments have been added with each line for an explanation. Run the above code and check your database, you will see a new table named “notifications” and also a new row is inserted in that table. Now we need to display this on the user side.

2. Display the counter in the title bar

We just need to fetch the total number of unread notifications from the database and display them in the user’s title bar. Create a new file named “index.php” and it will have the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
 
    // start session and login the user
    session_start();
 
    // you might be saving the session during login,
    // I am hard-coding the value for testing purpose
    $_SESSION["user_id"] = 565;
 
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
    // get number of unread notifications
    $sql = "SELECT COUNT(*) AS total_unread_notifications FROM notifications WHERE user_id = ? AND is_read = 0";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $_SESSION["user_id"]
    ]);
    $row = $statement->fetch();
    $total_unread_notifications = $row["total_unread_notifications"];

Then we need to fetch this variable in Javascript and prepend it in the title bar. First, we need to create a title tag and a hidden input field where we will put the above variable value.

1
2
3
4
5
<!-- title where notification number will be displayed -->
<title>My Website</title>
 
<!-- save variables in hidden input field to access in Javascript -->
<input type="hidden" id="total-unread-notifications" value="<?php echo $total_unread_notifications; ?>" />

Then we need to get this input field value in Javascript and render it in the title tag. We will create a separate Javascript function to render the title bar because we will need it in multiple situations when:

  1. The page is loaded
  2. There is a new notification (increment)
  3. A notification is read by the user (decrement)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<script>
 
    // get variables in Javascript
    var totalUnreadNotifications = document.getElementById("total-unread-notifications").value;
    totalUnreadNotifications = parseInt(totalUnreadNotifications);
 
    // show count in title bar
    showTitleBarNotifications();
 
    function showTitleBarNotifications() {
        // pattern to check if there is any counter number at the start of title bar
        var pattern = /^\(\d+\)/;
 
        if (totalUnreadNotifications == 0) {
            document.title = document.title.replace(pattern, "");
            return;
        }
 
        if (pattern.test(document.title)) {
 
            // update the counter
            document.title = document.title.replace(pattern, "(" + totalUnreadNotifications + ")");
        } else {
 
            // prepend the counter
            document.title = "(" + totalUnreadNotifications + ") " + document.title;
        }
    }
</script>

This will first check if the value of variable totalUnreadNotifications is greater than 0. If it is 0, then we will not show any number at all (not even 0). Then we will check if there is already any value in the title bar. If there is any value, then we will simply increment the counter value and re-render the title bar.

If there isn’t any value already in the title bar, then we will simply prepend the counter before the title tag content.

Here, the document.title is the only line that change title text.

This does change title text because initially, it was only “My Website”. After a notification is fetched from database, it prepends the value in the <title> tag.

At this point, you are seeing the number of unread notifications in your title bar. Now you need to find a way to mark notifications as “read” and decrement the counter.

3. Show all unread notifications to the user

To mark notifications as “read”, we first must show all the notifications to the user which when clicked will be marked as “read”. After that, the counter will be decremented and the title tag will be re-rendered. We will create a new file named “notifications.php” to display all notifications to the user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?php
 
    // start session
    session_start();
 
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
    // get all notifications sorting by unread goes first
    $sql = "SELECT * FROM notifications WHERE user_id = ? ORDER BY is_read ASC";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $_SESSION["user_id"]
    ]);
    $notifications = $statement->fetchAll();

This will fetch all the notifications of the logged-in user. Now we need to display them in an HTML table. We will simply by displaying a notification message and a button to mark that notification as read.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- show all notifications in a table -->
<table>
    <tr>
        <th>Message</th>
        <th>Action</th>
    </tr>
 
    <?php foreach ($notifications as $notification): ?>
        <tr>
            <td><?php echo $notification['message']; ?></td>
            <td>
                <!-- show 'read' button only if the notification is un-read -->
                <?php if (!$notification['is_read']): ?>
                    <form onsubmit="return markAsRead();">
                        <input type="hidden" name="id" value="<?php echo $notification['id']; ?>" />
                        <input type="hidden" name="user_id" value="<?php echo $notification['user_id']; ?>" />
                        <input type="submit" value="Read" />
                    </form>
                <?php endif; ?>
            </td>
        </tr>
    <?php endforeach; ?>
</table>

If you refresh the page now, you will see a list of all notifications with the button “read”. On clicking that button, we need to call an AJAX request to the server to mark this notification as “read” in the MySQL database. We will be using Vanilla JS to do that, no jQuery or any other external library is being used.

Now we need to create this Javascript function that will actually send the AJAX request. We will be using AJAX because there will be a lot of notifications and it will not be a good idea to keep refreshing the page for each notification to be marked as read.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<script>
    // when the read button is clicked
    function markAsRead() {
        // prevent the form from submitting
        event.preventDefault();
 
        // get the form node
        var form = event.target;
 
        // create AJAX object
        var ajax = new XMLHttpRequest();
 
        // set method and URL of request
        ajax.open("POST", "read-notification.php", true);
 
        // when the status of request changes
        ajax.onreadystatechange = function () {
 
            // when the response is received from server
            if (this.readyState == 4) {
 
                // if the response is successful
                if (this.status == 200) {
 
                    // convert the JSON string into Javascript object
                    var data = JSON.parse(this.responseText);
                    console.log(data);
 
                    // if there is no error
                    if (data.status == "success") {
 
                        // remove the 'read' button
                        form.remove();
 
                        // [emit read notification event here]
                    }
                }
            }
        };
 
        // create form data object with the form
        var formData = new FormData(form);
 
        // send the AJAX request with the form data
        ajax.send(formData);
    }
</script>

This will prevent the form from redirecting and calling our Javascript code. After the notification is successfully marked as read from the server, we will remove the “read” button. The last thing we need is a server-side PHP file that will handle this request.

4. Mark notification as read

Now we need to create a new file named “read-notification.php” that will mark this notification as “read”. In this file, we will also check the user_id along with the notification ID to make sure that the notification we are marking is “read” is actually sent to the logged-in user.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
 
    // start the session
    session_start();
 
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
    // get ID from AJAX
    $id = $_POST["id"];
 
    // mark notification as read
    $sql = "UPDATE notifications SET is_read = 1 WHERE id = ? AND user_id = ?";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $id,
        $_SESSION["user_id"]
    ]);
 
    // send the response back to client
    echo json_encode([
        "status" => "success"
    ]);
    exit();

This file will first check that the notification ID sent from AJAX actually refers to the logged-in user. Because someone can try to tamper with the client-side code and mark any other user’s notification as “read”. So we must do server-side validation like above.

At this point, if you run the code now, you will be able to see all the notifications in an HTML table with a “Read” button. When clicked, will mark the notification as read and also will remove the “read” button.

If you refresh the “index.php” file, you will now see the counter in the title bar will be decremented. One more thing you can do is to make it real-time, so when there is any notification added, the counter will be incremented in the title bar. And also when the notification is read by the user, then the counter should be decremented automatically.

5. Make notifications real-time

Making these notifications in real-time is crucial. You might have used the WhatsApp Web where you will see that the counter in the title bar automatically gets incremented and decremented based on the number of new notifications you received and the notifications have you read.

Now we need to learn how you can implement this functionality in your project. We will be using the Socket IO JS library for this and we will also create a small Node JS server for this purpose. You can download Socket IO JS from their official site.

After downloading, you need to paste the JS file into your project. You also need to download and install Node JS in your system, you can download it from here.

Setting up Node JS server

After Node JS installation, open the command prompt or terminal in your project root directory and run the following command:

1
npm init

This will ask a couple of questions, you can press “enter” for all questions and it will automatically set the default answer. Then we need to install the required modules for this feature. Run the following command in your terminal:

1
npm install express http socket.io

This will install the Express, HTTP, and Socket IO module in your Node JS app. To start the server, we need to install another module globally named “nodemon“. So again, run the following command in your terminal:

1
npm install -g nodemon

Typically when you made changes in your code, you need to manually restart the Node JS server. But it slows down the process during development. So this module automatically restarts the server if there is any change in the server file.

Create a new file named “server.js“, this will be our Node JS server file. Paste the following code in that file, we will explain this in the next step:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// initialize express server
var express = require("express");
var app = express();
 
// create http server from express instance
var http = require("http").createServer(app);
 
// include socket IO
var socketIO = require("socket.io")(http, {
    cors: {
        origin: ["http://localhost"]
    }
});
 
// start the HTTP server at port 3000
http.listen(process.env.PORT || 3000, function () {
    console.log("Server started running...");
 
    // an array to save all connected users IDs
    var users = [];
 
    // called when the io() is called from client
    socketIO.on("connection", function (socket) {
 
        // called manually from client to connect the user with server
        socket.on("connected", function (id) {
            users[id] = socket.id;
        });
    });
});

In this file we are:

  1. Initializing the Express framework and also HTTP module.
  2. Including the Socket IO module. You can place your own server URL in the CORS origin array.
  3. Then we are starting the server at port 3000. We use process.env.PORT on deployment.
  4. When a new user is connected with a server, a unique socket ID is generated. We are saving each user’s socket ID in a local array along with his ID from the database.

Now is the time to start the server. Run the following command in your terminal to start the server.

1
nodemon server.js

If you check the terminal, you will see a message “Server started running…” this means that you are ready to send connect your client-side with this server.

Increment counter on new notification

Whenever a new notification is sent to the server, we need to automatically increment the counter in the title bar. We have already created a function in “index.php” that displays the counter in the title bar.

To add this feature we need to perform the following tasks:

  1. Connect socket IO JS on the “send-notification.php” file.
  2. Then emit (send) the notification event to the Node JS server along with the ID of the user.
  3. On the Node JS server-side, listen to that event and emit the event to the relative user.
  4. Connect socket IO JS on the “index.php” file.
  5. Listener for that new notification event.
  6. When that event is received, increment the counter and re-render the title.

The following code goes in the “send-notification.php” file after the notification is inserted in the database:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- save user id -->
<input type="hidden" id="user-id" value="<?php echo $user_id; ?>" />
 
<!-- include socket IO JS -->
<script src="socket.io.js"></script>
 
<script>
    // connect with Node JS server
    var socketIO = io("http://localhost:3000");
 
    // get user ID
    var userId = document.getElementById("user-id").value;
 
    // send notification to the server
    socketIO.emit("newNotification", userId);
</script>

We are already creating the $user_id variable in the first step. Then we are simply including the socket IO JS library and connect with the Node JS server. Getting the user ID from the hidden input field. And finally emitting an event to the server with a user ID.

In your “server.js” listen to this event and emit the event to the user with the same ID.

1
2
3
4
5
6
// when a new notification is received
socket.on("newNotification", function (userId) {
 
    // send notification to the selected user
    socketIO.to(users[userId]).emit("newNotification", userId);
});

The event has been dispatched from the server to the client. Now the client must listen to this event and when received should increment the counter and re-render the title. The following code goes in your “index.php“:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<!-- include socket IO JS -->
<script src="socket.io.js"></script>
 
<script>
    // connect with Node JS server
    var socketIO = io("http://localhost:3000");
 
    // connect user with Node JS server
    var userId = document.getElementById("user-id").value;
    socketIO.emit("connected", userId);
 
    // when a new notification is received
    socketIO.on("newNotification", function (data) {
        totalUnreadNotifications++;
        showTitleBarNotifications();
    });
</script>

Open “index.php” and “send-notification.php” in separate tabs and refresh both of these pages. Every time you refresh the send notification page, you will see the title of the index file gets incremented. Now we need to do the same for reading notifications, except that the title bar will be decremented whenever a notification is marked as read.

Decrement counter on reading notification

In “notifications.php” first, we need to include the socket IO JS library and connect with the server.

1
2
3
4
5
6
7
<!-- include socket IO JS -->
<script src="socket.io.js"></script>
 
<script>
    // connect with Node JS server
    var socketIO = io("http://localhost:3000");
</script>

Following code goes in the [emit read notification event here] section:

1
2
// send notification to the server
socketIO.emit("notificationRead", form.user_id.value);

Now we need to create a listener for this in our “server.js” file.

1
2
3
socket.on("notificationRead", function (userId) {
    socketIO.to(users[userId]).emit("notificationRead", userId);
});

Similarly, you need to create a listener on the user side too in the index.php file.

1
2
3
4
socketIO.on("notificationRead", function (data) {
    totalUnreadNotifications--;
    showTitleBarNotifications();
});

This also change title text, but this time it decrements the counter value.

Run the code now and refresh both of your browsers. And try to read some notifications, as soon as you read them, you will see that the counter in the title bar will be decremented too.

So that’s how you can change title text of an HTML page using vanilla Javascript.

Conclusion

So that’s how you can implement a real-time notification system in your website with an unread notification counter in the title bar using simple PHP, Javascript, and Node JS. There is no PHP or Javascript framework used in this tutorial, so you can work with it with any framework in your existing project.

That’s how you can change the title text of the browser tab. If you face any problems in following this, kindly do let me know in the comments section below.

Download source code

[wpdm_package id=’1415′]

Dynamic FAQ – PHP and MySQL

In this tutorial, we are going to teach you how to create a dynamic FAQ section on your website using PHP and MySQL. We will create simple CRUD (Create, Read, Update, Delete) operation using PHP PDO. FAQs will be added, updated, and deleted from the admin panel. And they will be displayed on the user side.

Usually, the FAQ section is displayed statically. But it would be great if you can manage it from your admin panel. That’s why we should choose dynamic FAQ section over hard-coded one.

Table of content:

  1. Add FAQ from the admin panel
  2. Display all FAQs to the admin
  3. Edit any FAQ
  4. Delete FAQ
  5. Display FAQs on the user side

We will be using PHP PDO prepared statements to prevent SQL injection. We will be using bootstrap, jQuery, font-awesome, and richText libraries in this tutorial. All source files can be downloaded at the end of this article. Download all these libraries and paste them into your project.

1. Add FAQ

First, we will create a file named “add.php“. In this file, we will first include the above libraries.

1
2
3
4
5
6
7
8
<!-- include bootstrap, font awesome and rich text library CSS -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="richtext/richtext.min.css" />
<!-- include jquer, bootstrap and rich text JS -->
<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/bootstrap.js"></script>
<script src="richtext/jquery.richtext.js"></script>

Then we will create a form that will display input fields for the question and its answer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- layout for form to add FAQ -->
<div class="container" style="margin-top: 50px; margin-bottom: 50px;">
    <div class="row">
        <div class="offset-md-3 col-md-6">
            <h1 class="text-center">Add FAQ</h1>
            <!-- for to add FAQ -->
            <form method="POST" action="add.php">
                <!-- question -->
                <div class="form-group">
                    <label>Enter Question</label>
                    <input type="text" name="question" class="form-control" required />
                </div>
                <!-- answer -->
                <div class="form-group">
                    <label>Enter Answer</label>
                    <textarea name="answer" id="answer" class="form-control" required></textarea>
                </div>
                <!-- submit button -->
                <input type="submit" name="submit" class="btn btn-info" value="Add FAQ" />
            </form>
        </div>
    </div>
    [show all FAQs here]
</div>

Then you need to initialize the richText library to make the textarea field with more options like text styles, fonts, lists, tables, and images, etc. Following Javascript code will do that:

1
2
3
4
// initialize rich text library
window.addEventListener("load", function () {
    $("#answer").richText();
});

Then we will handle this request in the same file. We will create the required table in the MySQL database dynamically. Then we will insert a new row with questions and answers entered in input fields.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
    // check if insert form is submitted
    if (isset($_POST["submit"]))
    {
        // create table if not already created
        $sql = "CREATE TABLE IF NOT EXISTS faqs (
            id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
            question TEXT NULL,
            answer TEXT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP
        )";
        $statement = $conn->prepare($sql);
        $statement->execute();
        // insert in faqs table
        $sql = "INSERT INTO faqs (question, answer) VALUES (?, ?)";
        $statement = $conn->prepare($sql);
        $statement->execute([
            $_POST["question"],
            $_POST["answer"]
        ]);
    }
    // [query to get all FAQs]
?>

Run the code now and you will be able to see a form with 2 input fields. When hit submit, you will see a new table will be created in your database. And a new row will be inserted in that table. Add a few more questions and their answers using the form.

2. Display all FAQ

Now we need to display all added FAQs to the admin side. In the same add.php file, the following code goes in the [query to get all FAQs] section:

1
2
3
4
5
// get all faqs from latest to oldest
$sql = "SELECT * FROM faqs ORDER BY id DESC";
$statement = $conn->prepare($sql);
$statement->execute();
$faqs = $statement->fetchAll();

This will fetch all the questions sorted by newest to oldest. Now we need to display all of them on a table. The following code goes in the [show all FAQs here] section:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!-- show all FAQs added -->
<div class="row">
    <div class="offset-md-2 col-md-8">
        <table class="table table-bordered">
            <!-- table heading -->
            <thead>
                <tr>
                    <th>ID</th>
                    <th>Question</th>
                    <th>Answer</th>
                    <th>Actions</th>
                </tr>
            </thead>
            <!-- table body -->
            <tbody>
                <?php foreach ($faqs as $faq): ?>
                    <tr>
                        <td><?php echo $faq["id"]; ?></td>
                        <td><?php echo $faq["question"]; ?></td>
                        <td><?php echo $faq["answer"]; ?></td>
                        <td>
                            [edit button goes here]
                            [delete button goes here]
                        </td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>
</div>

Refresh the page now and you will be able to view all the inserted questions sorting by newest to oldest.

3. Edit any FAQ

Following are the steps to update any specific row in the MySQL database using PHP PDO prepared statement:

  1. Show a link to go to edit page with each row
  2. Fetch the row data from MySQL using ID from URL
  3. Create a same form like add.php
  4. Auto-populate the values in the input fields
  5. Create a hidden input field for ID
  6. Update the data in database using ID
  7. Redirect to previous page

1. Show a link to go to edit page

Following code goes in the [edit button goes here] section:

1
2
3
4
<!-- edit button -->
<a href="edit.php?id=<?php echo $faq['id']; ?>" class="btn btn-warning btn-sm">
    Edit
</a>

Refresh the page now and you will see an edit link with each row. Then create a file named “edit.php” that will handle this request.

2. Fetch the row from MySQL

You will see an ID in the URL in the browser’s address bar. We need to get this value and search it in the MySQL database. This file will be similar to add.php but with auto-populate values in the input fields. First, we will fetch the row from the database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
    // check if FAQ exists
    $sql = "SELECT * FROM faqs WHERE id = ?";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $_REQUEST["id"]
    ]);
    $faq = $statement->fetch();
    if (!$faq)
    {
        die("FAQ not found");
    }
    // [update query goes here]
?>

This will fetch the row from the database using the ID from the URL. If the row is not found, then it will display an error and stop the script.

3, 4 & 5. Create form with auto-populate values

This form will use the above $faq variable to display the values in input fields.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<!-- include CSS -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.css" />
<link rel="stylesheet" type="text/css" href="richtext/richtext.min.css" />
<!-- include JS -->
<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/bootstrap.js"></script>
<script src="richtext/jquery.richtext.js"></script>
<!-- layout for form to edit FAQ -->
<div class="container" style="margin-top: 50px; margin-bottom: 50px;">
    <div class="row">
        <div class="offset-md-3 col-md-6">
            <h1 class="text-center">Edit FAQ</h1>
            <!-- form to edit FAQ -->
            <form method="POST" action="edit.php">
                <!-- hidden ID field of FAQ -->
                <input type="hidden" name="id" value="<?php echo $faq['id']; ?>" required />
                <!-- question, auto-populate -->
                <div class="form-group">
                    <label>Enter Question</label>
                    <input type="text" name="question" class="form-control" value="<?php echo $faq['question']; ?>" required />
                </div>
                <!-- answer, auto-populate -->
                <div class="form-group">
                    <label>Enter Answer</label>
                    <textarea name="answer" id="answer" class="form-control" required><?php echo $faq['answer']; ?></textarea>
                </div>
                <!-- submit button -->
                <input type="submit" name="submit" class="btn btn-warning" value="Edit FAQ" />
            </form>
        </div>
    </div>
</div>
<script>
    // initialize rich text library
    window.addEventListener("load", function () {
        $("#answer").richText();
    });
</script>

If you refresh the page now, you will see the same form as the added FAQ but the input fields are auto-populated with selected FAQ values. It will also have a hidden input field for the ID.

6 & 7. Update the data and redirect back

Now we need to handle the update request. In the edit.php file, replace the [update query goes here] section with the following code to update the data in the database.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// check if edit form is submitted
if (isset($_POST["submit"]))
{
    // update the FAQ in database
    $sql = "UPDATE faqs SET question = ?, answer = ? WHERE id = ?";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $_POST["question"],
        $_POST["answer"],
        $_POST["id"]
    ]);
    // redirect back to previous page
    header("Location: " . $_SERVER["HTTP_REFERER"]);
}

Refresh the page now and try to update any FAQ. You will see that it will be updated in the MySQL database as well as in the HTML table too.

4. Delete FAQ

First, we need to show a delete button with each row. It will be a form with a hidden input field that contains the value of that FAQ. When that form is submitted, we will again first check if the record exists in the database. If yes, then we will simply remove it.

The following code goes in the [delete button goes here] section of the add.php file:

1
2
3
4
5
<!-- delete form -->
<form method="POST" action="delete.php" onsubmit="return confirm('Are you sure you want to delete this FAQ ?');">
    <input type="hidden" name="id" value="<?php echo $faq['id']; ?>" required />
    <input type="submit" value="Delete" class="btn btn-danger btn-sm" />
</form>

Then we need to create a new file named “delete.php” that will handle this request.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?php
    // connect database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
    // check if FAQ existed
    $sql = "SELECT * FROM faqs WHERE id = ?";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $_REQUEST["id"]
    ]);
    $faq = $statement->fetch();
    if (!$faq)
    {
        die("FAQ not found");
    }
    // delete from database
    $sql = "DELETE FROM faqs WHERE id = ?";
    $statement = $conn->prepare($sql);
    $statement->execute([
        $_POST["id"]
    ]);
    // redirect to previous page
    header("Location: " . $_SERVER["HTTP_REFERER"]);
?>

If you refresh the page now, you will see a red delete button with each row. On clicking, it will ask for confirmation. When confirmed, it will remove the FAQ from the MySQL database using PHP.

5. Display FAQs on the user side

Now comes the final part, where we will display our dynamic FAQ on the user side. Typically we have an index.php as our website home page. But you might have a separate page for FAQs. Either way, you first need to fetch all the data from the database:

1
2
3
4
5
6
7
8
9
<?php
    // connect with database
    $conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
    // fetch all FAQs from database
    $sql = "SELECT * FROM faqs";
    $statement = $conn->prepare($sql);
    $statement->execute();
    $faqs = $statement->fetchAll();
?>

After that, we will be using Bootstrap’s panel to display the data as an accordion.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!-- include CSS -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.css" />
<!-- include JS -->
<script src="js/jquery-3.3.1.min.js"></script>
<script src="js/bootstrap.js"></script>
<!-- show all FAQs in a panel -->
<div class="container" style="margin-top: 50px; margin-bottom: 50px;">
    <div class="row">
        <div class="col-md-12 accordion_one">
            <div class="panel-group">
                <?php foreach ($faqs as $faq): ?>
                    <div class="panel panel-default">
                        <!-- button to show the question -->
                        <div class="panel-heading">
                            <h4 class="panel-title">
                                <a data-toggle="collapse" data-parent="#accordion_oneLeft" href="#faq-<?php echo $faq['id']; ?>" aria-expanded="false" class="collapsed">
                                    <?php echo $faq['question']; ?>
                                </a>
                            </h4>
                        </div>
                        <!-- accordion for answer -->
                        <div id="faq-<?php echo $faq['id']; ?>" class="panel-collapse collapse" aria-expanded="false" role="tablist" style="height: 0px;">
                            <div class="panel-body">
                                <div class="text-accordion">
                                    <?php echo $faq['answer']; ?>
                                </div>
                            </div>
                        </div>
                    </div>
                <?php endforeach; ?>
            </div>
        </div>
    </div>
</div>

Finally, you can apply some CSS styles to make it look better.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
.accordion_one .panel-group {
    border: 1px solid #f1f1f1;
    margin-top: 100px
}
a:link {
    text-decoration: none
}
.accordion_one .panel {
    background-color: transparent;
    box-shadow: none;
    border-bottom: 0px solid transparent;
    border-radius: 0;
    margin: 0
}
.accordion_one .panel-default {
    border: 0
}
.accordion-wrap .panel-heading {
    padding: 0px;
    border-radius: 0px
}
h4 {
    font-size: 18px;
    line-height: 24px
}
.accordion_one .panel .panel-heading a.collapsed {
    color: #999999;
    display: block;
    padding: 12px 30px;
    border-top: 0px
}
.accordion_one .panel .panel-heading a {
    display: block;
    padding: 12px 30px;
    background: #fff;
    color: #313131;
    border-bottom: 1px solid #f1f1f1
}
.accordion-wrap .panel .panel-heading a {
    font-size: 14px
}
.accordion_one .panel-group .panel-heading+.panel-collapse>.panel-body {
    border-top: 0;
    padding-top: 0;
    padding: 25px 30px 30px 35px;
    background: #fff;
    color: #999999
}
.img-accordion {
    width: 81px;
    float: left;
    margin-right: 15px;
    display: block
}
.accordion_one .panel .panel-heading a.collapsed:after {
    content: "\2b";
    color: #999999;
    background: #f1f1f1
}
.accordion_one .panel .panel-heading a:after,
.accordion_one .panel .panel-heading a.collapsed:after {
    font-family: 'FontAwesome';
    font-size: 15px;
    width: 36px;
    line-height: 48px;
    text-align: center;
    background: #F1F1F1;
    float: left;
    margin-left: -31px;
    margin-top: -12px;
    margin-right: 15px
}
.accordion_one .panel .panel-heading a:after {
    content: "\2212"
}
.accordion_one .panel .panel-heading a:after,
.accordion_one .panel .panel-heading a.collapsed:after {
    font-family: 'FontAwesome';
    font-size: 15px;
    width: 36px;
    height: 48px;
    line-height: 48px;
    text-align: center;
    background: #F1F1F1;
    float: left;
    margin-left: -31px;
    margin-top: -12px;
    margin-right: 15px
}

Run the code now and you will see a beautiful accordion with a question, which when clicked will display an answer. You can add as many questions and their answer from the database and they will be displayed here automatically.

So that’s how you can create a dynamic FAQ section on your website that can be managed from your admin panel.

Learn how to add dynamic testimonial section on your website from here.

Source code:

Dynamic testimonial – PHP & MySQL, Vue JS

In this tutorial, we are going to teach you how you can add a dynamic testimonial to your website using PHP and MySQL in the backend and Vue JS in the frontend. Testimonials are displayed on a website to show the new users how your product satisfies your previous customers. We will be creating 2 pages, one for adding testimonials from the admin panel. And second to display all testimonials in a beautiful design.

If you do not have a dynamic testimonial, then you have to manually add, modify or delete a testimonial from your website. By going dynamic, you can perform all these actions from your admin panel.

Add Testimonial

First, download Bootstrap from here and Vue JS from here. Paste the CSS and JS files in your project, we will be using them in a moment. After that, we need to create a form from which we can add testimonials. Each testimonial will have a picture of the person, name, designation in his company, and his comments.

The following code goes in your admin panel from where you want to add testimonials.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!-- include bootstrap -->
<link rel="stylesheet" type="text/css" href="bootstrap.min.css" />
  
<!-- include vue js -->
<script src="vue.min.js"></script>
 
<!-- container for vue js app -->
<div class="container" style="margin-top: 50px; margin-bottom: 50px;" id="addTestimonialApp">
    <div class="row">
        <!-- center align form -->
        <div class="offset-md-3 col-md-6">
            <h2 style="margin-bottom: 30px;">Add Testimonial</h2>
  
            <!-- form to add testimonial -->
            <form v-on:submit.prevent="store" enctype="multipart/form-data">
 
                <!-- picture of user -->
                <div class="form-group">
                    <label>Picture</label>
                    <input type="file" name="picture" accept="image/*" class="form-control" />
                </div>
 
                <!-- name of user -->
                <div class="form-group">
                    <label>Name</label>
                    <input type="text" name="name" class="form-control" />
                </div>
 
                <!-- designation of user -->
                <div class="form-group">
                    <label>Designation</label>
                    <input type="text" name="designation" class="form-control" />
                </div>
 
                <!-- comment -->
                <div class="form-group">
                    <label>Comment</label>
                    <textarea name="comment" class="form-control"></textarea>
                </div>
 
                <!-- submit button -->
                <input type="submit" name="submit" class="btn btn-info" value="Add Testimonial" />
            </form>
        </div>
    </div>
 
    [show all testimonials for deleting]
</div>

This will show a form with input fields. But when you click on the “Add Testimonial” button, nothing happens. This is because we need to render it using Vue JS.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<script>
    // initialize vue js app
    var addTestimonialApp = new Vue({
        el: "#addTestimonialApp", // id of container div
        data: {
            // all values used in this app
            testimonials: []
        },
        // all methods
        methods: {
            // [other methods goes here]
 
             // called when form is submitted
            store: function () {
                // get this app instance
                var self = this;
                var form = event.target;
              
                // call an AJAX to create a new entry in testimonials
                var ajax = new XMLHttpRequest();
                ajax.open("POST", "store.php", true);
              
                ajax.onreadystatechange = function () {
                    if (this.readyState == 4) { // response received
                        if (this.status == 200) { // response is successfull
                            // console.log(this.responseText);
              
                            // parse the response from JSON string to JS arrays and objects
                            var response = JSON.parse(this.responseText);
                            // console.log(response);
 
                            alert(response.message);
              
                            // if there is no error
                            if (response.status == "success") {
                                self.testimonials.unshift(response.testimonial);
                                form.reset();
                            } else {
                                // when there is any error
                            }
                        }
              
                        if (this.status == 500) {
                            console.log(this.responseText);
                        }
                    }
                };
              
                // create form data object and form to it
                var formData = new FormData(form);
              
                // actually sending the request
                ajax.send(formData);
            },
        },
 
        // [mount code goes here]
    });
</script>

Refresh the page now and you will be able to submit the form, this is because of Vue JS. An AJAX request will be sent to the server to store the picture attached and save the other fields in the MySQL database using PHP.

Create a new file named “store.php” and paste the following code in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php
  
// connect with database
$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
// create tables if not exists
$sql = "CREATE TABLE IF NOT EXISTS testimonials (
    id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,
    picture TEXT NULL,
    name VARCHAR(255) NULL,
    designation VARCHAR(255) NULL,
    comment TEXT NOT NULL,
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)";
$result = $conn->prepare($sql);
$result->execute();
 
$file_path = "";
if ($_FILES["picture"]["error"] == 0)
{
    $folder_name = "testimonials";
    mkdir($folder_name);
    $file_path = $folder_name . "/" . $_FILES["picture"]["name"];
    move_uploaded_file($_FILES["picture"]["tmp_name"], $file_path);
}
 
// insert in testimonials table
$sql = "INSERT INTO testimonials (picture, name, designation, comment, created_at) VALUES (?, ?, ?, ?, NOW())";
$result = $conn->prepare($sql);
$result->execute([
    $file_path,
    $_POST["name"],
    $_POST["designation"],
    $_POST["comment"],
]);
$testimonial_id = $conn->lastInsertId();
 
// get the testimonial just inserted in database
$sql = "SELECT * FROM testimonials WHERE id = ?";
$result = $conn->prepare($sql);
$result->execute([
    $testimonial_id
]);
$testimonial = $result->fetch();
 
echo json_encode([
    "status" => "success",
    "message" => "Testimonial has been added.",
    "testimonial" => $testimonial
]);
exit();

If you refresh the page now, upload the picture, enter the fields and hit submit, it will create a new table in the database if not already created. Then it will create a folder named “testimonials” and save the image file in it. Then it will insert a new row in it. And finally, it will return the new row back to the client (AJAX).

From there we will prepend it in our local testimonials array. Now we need to display all the added testimonials in an HTML table with a button to delete them.

Display all Testimonials to Admin

The following code goes in the [show all testimonials for deleting] section:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!-- show all testimonials -->
<div class="row" style="margin-top: 50px;">
    <div class="col-md-12">
        <table class="table table-bordered">
            <!-- table heading -->
            <tr>
                <th>ID</th>
                <th>Picture</th>
                <th>Name</th>
                <th>Designation</th>
                <th>Comment</th>
                <th>Actions</th>
            </tr>
  
            <!-- loop through an array of testimonials -->
            <tr v-for="(testimonial, index) in testimonials">
                <td v-text="testimonial.id"></td>
                <td>
                    <img v-bind:src="testimonial.picture" style="width: 300px;" />
                </td>
                <td v-text="testimonial.name"></td>
                <td v-text="testimonial.designation"></td>
                <td v-text="testimonial.comment"></td>
                <td>
                    <!-- form to delete testimonial -->
                    <form v-on:submit.prevent="deleteTestimonial">
                        <input type="hidden" name="id" v-model="testimonial.id" required />
                        <input type="submit" class="btn btn-danger btn-sm" value="Delete" />
                    </form>
                </td>
            </tr>
        </table>
    </div>
</div>

This will create an empty HTML table because we need to load the in it first. We will call an AJAX to fetch all the stored testimonials using PHP and MySQL and display them using Vue JS. The following code goes in the [mount code goes here] section:

1
2
3
mounted: function () {
    this.getData();
}

Now we need to create a function named “getData” in our Vue JS instance. Replace the code in section [other methods goes here] with the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// [delete method]
 
getData: function () {
    // get this app instance
    var self = this;
  
    // call an AJAX to get all testimonials
    var ajax = new XMLHttpRequest();
    ajax.open("POST", "fetch.php", true);
  
    ajax.onreadystatechange = function () {
        if (this.readyState == 4) { // response received
            if (this.status == 200) { // response is successfull
                // console.log(this.responseText);
  
                // parse the response from JSON string to JS arrays and objects
                var response = JSON.parse(this.responseText);
                // console.log(response);
  
                // if there is no error
                if (response.status == "success") {
                    self.testimonials = response.data;
                } else {
                    // when there is any error
                }
            }
  
            if (this.status == 500) {
                console.log(this.responseText);
            }
        }
    };
  
    // create form data object
    var formData = new FormData();
  
    // actually sending the request
    ajax.send(formData);
},

Finally, we need to create a new file named “fetch.php” that will fetch all the testimonials from the MySQL database using PHP.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<?php
 
// connect with database
$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
// fetch all testimonials
$sql = "SELECT * FROM testimonials ORDER BY id DESC";
$statement = $conn->prepare($sql);
$statement->execute();
$data = $statement->fetchAll();
 
// create new field for full comment text
// because we will be displaying less text and display 'show more' button
for ($a = 0; $a < count($data); $a++)
{
    $data[$a]["comment_full"] = $data[$a]["comment"];
    $data[$a]["comment"] = substr($data[$a]["comment"], 0, 50);
}
 
// send the response back to client
echo json_encode([
    "status" => "success",
    "message" => "Testimonial has been fetched.",
    "data" => $data
]);
exit();
 
?>

Refresh the page now and you will be able to see all the testimonials added. Also, if you add a new testimonial, it will automatically be prepended in the HTML table. Now we need to make it able to delete the testimonial.

Delete Testimonial

We need to follow the following steps to delete the testimonial:

  1. Call an AJAX with an ID of testimonial.
  2. On server side, fetch the testimonial using ID.
  3. Delete the picture from the “testimonials” folder using PHP unlink() function.
  4. Delete the testimonial from MySQL database.
  5. Send the response back to client.
  6. The client will remove the testimonial from local array.
  7. It will automatically be removed from the HTML table.

Replace the section [delete method] with the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// method to delete testimonial
deleteTestimonial: function () {
    // get this app instance
    var self = this;
  
    // get form
    var form = event.target;
  
    // call an AJAX to delete the testimonial
    var ajax = new XMLHttpRequest();
    ajax.open("POST", "delete.php", true);
  
    ajax.onreadystatechange = function () {
        if (this.readyState == 4) { // response received
            if (this.status == 200) { // response is successfull
                // console.log(this.responseText);
  
                // parse the response from JSON string to JS arrays and objects
                var response = JSON.parse(this.responseText);
                console.log(response);
  
                // remove from local array if deleted from server
                if (response.status == "success") {
                    for (var a = 0; a < self.testimonials.length; a++) {
                        var testimonial = self.testimonials[a];
                        if (testimonial.id == form.id.value) {
                            self.testimonials.splice(a, 1);
                            break;
                        }
                    }
                } else {
                    // display an error message
                    alert(response.message);
                }
            }
  
            if (this.status == 500) {
                console.log(this.responseText);
            }
        }
    };
  
    // append form in form data object
    var formData = new FormData(form);
  
    // call AJAX with form data
    ajax.send(formData);
},

Then we need to create a new file named “delete.php” that will handle this request. It will have the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<?php
  
// connect with database
$conn = new PDO("mysql:host=localhost;dbname=test", "root", "");
 
// get the testimonial just inserted in database
$sql = "SELECT * FROM testimonials WHERE id = ?";
$result = $conn->prepare($sql);
$result->execute([
    $_POST["id"]
]);
$testimonial = $result->fetch();
 
if (!$testimonial)
{
    // send the response back to client
    echo json_encode([
        "status" => "error",
        "message" => "Testimonial not found."
    ]);
    exit();
}
 
// remove the picture from folder
unlink($testimonial["picture"]);
 
// create a query to delete the pricing table from database
$sql = "DELETE FROM testimonials WHERE id = ?";
  
// prepare the query
$result = $conn->prepare($sql);
  
// execute the query
$result->execute([
    $_POST["id"]
]);
  
// send the response back to client
echo json_encode([
    "status" => "success",
    "message" => "Testimonial has been deleted."
]);
exit();

Refresh the page now and you will be able to delete the testimonials as well. The only thing left is to show the testimonials on the user side.

Display Testimonials on User Side

To display testimonials on the user side, you need to download font-awesome and slick, you already have the Bootstrap and Vue JS files in your project folder. You can download font-awesome from here and slick from here. After downloading, paste both folders into your project, we will include them on your user side.

The following code will display the layout for each testimonial using HTML. Which we will render using Vue JS in the next step.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
<!-- include bootstrap CSS -->
<link rel="stylesheet" type="text/css" href="bootstrap.min.css" />
 
<!-- include font awesome -->
<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.min.css" />
 
<!-- include slick -->
<link rel="stylesheet" type="text/css" href="slick.css" />
<link rel="stylesheet" type="text/css" href="slick-theme.css" />
 
<!-- include vue js -->
<script src="vue.min.js"></script>
 
<div class="container" id="testimonialApp" style="margin-top: 30px;">
    <div class="row">
        <div class="col-md-12">
            <h2 class="text-center">Testimonials</h2>
        </div>
    </div>
 
    <div class="row">
        <div class="col-md-12">
            <div class="items">
 
                <div class="card" v-for="(testimonial, index) in testimonials">
                    <div class="card-body">
                        <h4 class="card-title">
                            <img src="https://img.icons8.com/ultraviolet/40/000000/quote-left.png" />
                        </h4>
                         
                        <div class="template-demo">
                            <p>
                                <span v-text="testimonial.comment"></span>
 
                                <span class="show-more-text" v-on:click="loadMoreContent" v-bind:data-index="index">show more</span>
                            </p>
                        </div>
 
                        <h4 class="card-title">
                            <img src="https://img.icons8.com/ultraviolet/40/000000/quote-right.png" style="margin-left: auto;" />
                        </h4>
                         
                        <hr />
                         
                        <div class="row">
                            <div class="col-sm-3">
                                <img class="profile-pic" v-bind:src="testimonial.picture" />
                            </div>
                             
                            <div class="col-sm-9">
                                <div class="profile">
                                    <h4 class="cust-name" v-text="testimonial.name"></h4>
                                    <p class="cust-profession" v-text="testimonial.designation"></p>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
                 
            </div>
        </div>
    </div>
</div>
 
<!-- include jquery -->
<script src="jquery-3.3.1.min.js"></script>
 
<script src="slick.min.js"></script>
 
<!-- include bootstrap JS -->
<script src="bootstrap.min.js"></script>
 
<!-- your JS code -->
<script src="script.js?v=<?php echo time(); ?>"></script>

Create a new file named “script.js” and paste the following code in it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
var mainURL = window.location.origin + "/" + window.location.pathname + "/";
 
var testimonialApp = new Vue({
    el: "#testimonialApp",
    data: {
        testimonials: []
    },
    methods: {
        loadMoreContent: function () {
            var node = event.target;
            var index = node.getAttribute("data-index");
 
            if (this.testimonials[index].comment.length > 50) {
                // it needs to display less
                node.innerHTML = "show more";
                this.testimonials[index].comment = this.testimonials[index].comment_full.substr(0, 50);
            } else {
                // it needs to display more
                node.innerHTML = "show less";
                this.testimonials[index].comment = this.testimonials[index].comment_full;
            }
        },
 
        getData: function () {
            // get this app instance
            var self = this;
          
            // call an AJAX to get all testimonials
            var ajax = new XMLHttpRequest();
            ajax.open("POST", "fetch.php", true);
          
            ajax.onreadystatechange = function () {
                if (this.readyState == 4) { // response received
                    if (this.status == 200) { // response is successfull
                        // console.log(this.responseText);
          
                        // parse the response from JSON string to JS arrays and objects
                        var response = JSON.parse(this.responseText);
                        // console.log(response);
          
                        // if there is no error
                        if (response.status == "success") {
                            self.testimonials = response.data;
 
                            setTimeout(function () {
                                $('.items').slick({
                                    dots: true,
                                    infinite: true,
                                    speed: 800,
                                    autoplay: false,
                                    slidesToShow: 2,
                                    slidesToScroll: 2,
                                    responsive: [{
                                            breakpoint: 1024,
                                            settings: {
                                                slidesToShow: 3,
                                                slidesToScroll: 3,
                                                infinite: true,
                                                dots: true
                                            }
                                        }, {
                                            breakpoint: 600,
                                            settings: {
                                                slidesToShow: 2,
                                                slidesToScroll: 2
                                            }
                                        }, {
                                            breakpoint: 480,
                                            settings: {
                                                slidesToShow: 1,
                                                slidesToScroll: 1
                                            }
                                        }
                                    ]
                                });
                            }, 100);
                        } else {
                            // when there is any error
                        }
                    }
          
                    if (this.status == 500) {
                        console.log(this.responseText);
                    }
                }
            };
          
            // create form data object
            var formData = new FormData();
          
            // actually sending the request
            ajax.send(formData);
        }
    },
    mounted: function () {
        this.getData();
    }
});

At this point, you will be able to view the testimonials added from the admin panel on your website. It will also have a carousel slider. Finally, you can apply some CSS styles to make it look better for the users.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
<style>
    .show-more-text {
        background-color: #72a4d5;
        color: white;
        padding: 3px 5px;
        border-radius: 5px;
        margin-left: 3px;
        cursor: pointer;
    }
    .more {
        display: none;
    }
 
    @media (max-width:991.98px) {
        .padding {
            padding: 1.5rem
        }
    }
 
    @media (max-width:767.98px) {
        .padding {
            padding: 1rem
        }
    }
 
    .padding {
        padding: 5rem
    }
 
    .card {
        position: relative;
        display: flex;
        width: 350px;
        flex-direction: column;
        min-width: 0;
        word-wrap: break-word;
        background-color: #fff;
        background-clip: border-box;
        border: 1px solid #d2d2dc;
        border-radius: 11px;
        -webkit-box-shadow: 0px 0px 5px 0px rgb(249, 249, 250);
        -moz-box-shadow: 0px 0px 5px 0px rgba(212, 182, 212, 1);
        box-shadow: 0px 0px 5px 0px rgb(161, 163, 164)
    }
 
    .card .card-body {
        padding: 1rem 1rem
    }
 
    .card-body {
        flex: 1 1 auto;
        padding: 1.25rem
    }
 
    p {
        font-size: 0.875rem;
        margin-bottom: .5rem;
        line-height: 1.5rem
    }
 
    h4 {
        line-height: .2 !important
    }
 
    .profile {
        margin-top: 16px;
        margin-left: 11px
    }
 
    .profile-pic {
        width: 100px;
    }
 
    .cust-name {
        font-size: 18px
    }
 
    .cust-profession {
        font-size: 10px
    }
 
    .items {
        width: 90%;
        margin: 0px auto;
        margin-top: 30px
    }
 
    .slick-slide {
        margin: 10px;
        height: auto !important;
    }
</style>

So that’s it, you have a dynamic testimonial section fully manageable from the admin panel. If you face any problems in following this, kindly do let us know in the comments section below.

Also learn how to add dynamic pricing table in your website.

Download

[wpdm_package id=’1399′]