[FRAMEWORK] Xây dựng page Account Phần 2 (ok)

Add follow, Unfollow

Add Follow

C:\Users\Administrator\Downloads\wp_notification.sql

-- phpMyAdmin SQL Dump
-- version 5.1.3
-- https://www.phpmyadmin.net/
--
-- Host: 127.0.0.1
-- Generation Time: Jul 26, 2022 at 09:15 PM
-- Server version: 10.4.24-MariaDB
-- PHP Version: 7.4.28
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
START TRANSACTION;
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8mb4 */;
--
-- Database: `reset2`
--
-- --------------------------------------------------------
--
-- Table structure for table `wp_notification`
--
CREATE TABLE `wp_notification` (
  `id` bigint(20) NOT NULL,
  `from_` bigint(20) NOT NULL,
  `to_` bigint(20) NOT NULL,
  `type` varchar(20) COLLATE utf8mb4_unicode_ci NOT NULL,
  `content` varchar(225) COLLATE utf8mb4_unicode_ci NOT NULL,
  `status` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `time_created` timestamp NOT NULL DEFAULT current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
--
-- Dumping data for table `wp_notification`
--
INSERT INTO `wp_notification` (`id`, `from_`, `to_`, `type`, `content`, `status`, `time_created`) VALUES
(8, 5, 2, 'has_like', '55', '', '2022-02-16 00:47:44'),
(9, 3, 2, 'has_like', '55', '', '2022-02-16 01:25:35'),
(10, 3, 2, 'has_comment', '55', '', '2022-02-16 01:58:10'),
(11, 3, 2, 'has_reply', '55', '', '2022-02-16 02:17:02'),
(14, 3, 2, 'has_follow', '', '', '2022-02-16 19:49:40'),
(15, 2, 5, 'invite_group', '13', '', '2022-02-16 23:14:09'),
(16, 2, 3, 'invite_group', '20', '', '2022-02-16 23:24:55'),
(17, 3, 17, 'group_new_post', '82', '', '2022-02-17 00:13:20'),
(19, 2, 6, 'invite_group', '22', '', '2022-02-20 21:51:04'),
(20, 2, 22, 'group_new_post', '85', '', '2022-02-20 21:51:56'),
(21, 2, 3, 'invite_group', '22', '', '2022-02-20 21:54:19'),
(22, 2, 3, 'has_follow', '', '', '2022-02-20 22:05:15'),
(23, 1, 2, 'has_follow', '', '', '2022-07-26 18:52:16');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `wp_notification`
--
ALTER TABLE `wp_notification`
  ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `wp_notification`
--
ALTER TABLE `wp_notification`
  MODIFY `id` bigint(20) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=24;
COMMIT;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\controllers\Account.php

<?php
class BJ_Account_Controller extends Pv_Controller {
  function __construct() {
    if (isset($_GET['action'])):
      switch ($_GET['action']) {
      case "edit-info":
        $this->update_info();
        break;
      case "followers":
        $this->followers();
        break;
      default:
        $this->index();
      } else :
      $this->index();
    endif;
  }
  private function get_user_id() {
    if (isset($_GET["id"]) && is_user_exist(strip_tags($_GET["id"]))) {
      return $_GET["id"];
    } else {
      return get_current_user_id();
    }
  }
  public function index() {
    $data                         = array();
    $user_id                      = $this->get_user_id();
    $user_obj                     = get_userdata($user_id);
    $data['id']                   = $user_id;
    $data['display_name']         = $user_obj->display_name;
    $data['date_registered']      = date_i18n(__('jS F Y', 'umm'), strtotime($user_obj->user_registered));
    $data['avatar']               = get_url_avatar($user_id);
    $data['province_address_arr'] = atw_load_province_address($user_id);
    $this->load()->View("account", $data, "account");
  }
  public function update_info() {
    $data = array();
    $this->load()->View("update-info", $data, "account");
  }
  public function followers() {
    $current_user_id       = $this->get_user_id();
    $data                  = array();
    $data['list_follower'] = get_list_follower($current_user_id);
    $this->load()->View("followers", $data, "account");
  }
}

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\views\account\followers.php

<div class="page-followers container">
  <div class="list-follower mt-4">
  <?php if( $args['list_follower'] && is_array($args['list_follower']) ): ?>
    <?php
    foreach($args['list_follower'] as $user_id){
      $user_obj = get_userdata( $user_id );
      $avatar_img = get_url_avatar($user_id);
      $link_account = SITE_URL . "account/?id={$user_id}&appt=N";
      $display_name = $user_obj->display_name;
      $class = 'btn-follow__remove';
      $btn_text = __('Unfollow', 'umm');
      if ( !is_user_exist($user_id) ) continue;
      if(  !in_array( $user_id, list_user_follow() ) ) {
        $class = 'btn-follow__add';
        $btn_text = __('Follow', 'umm');
      }
      if ( $user_id == get_current_user_id() ){
        $class .= ' no-click';
      }
      ?>
      <div class="list-follower__item d-flex align-items-center justify-content-between border-b-1 py-2">
        <div class="list-follower__item__avatar">
          <a href="<?php echo $link_account ?>" class="d-block">
            <img src="<?php echo $avatar_img ?>" class="rounded-circle" width="60" height="60">
          </a>
        </div>
        <div class="list-follower__item__name flex-fill ml-4">
          <a href="<?php echo $link_account ?>"><?php echo $display_name; ?></a>
        </div>
        <button type="button" data-id="<?php echo $user_id; ?>" class="<?php echo $class ?> list-follower__item__button btn bg-primary text-white font-weight-600"> <?php echo $btn_text; ?> 
        </button>
      </div>
    <?php } ?>
  <?php endif; ?>
  </div>
</div>

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\inc\functions\function-global.php

<?php
/**
 *
 * @return HTML - option list tỉnh thành
 */
function reder_province_option($default = "") {
  $json_file = get_stylesheet_directory() . "/json/tinh_tp.json";
  if (file_exists($json_file)) {
    $json       = file_get_contents($json_file);
    $tinh_thanh = json_decode($json, true);
    foreach ($tinh_thanh as $key => $value) {
      if ($key == $default) {$select = "selected";} else { $select = "";}
      echo "<option " . $select . " value='" . $key . "'>" . $value["name"] . "</option>";
    }
  }
}
/**
 * @return HTML - option list quận huyện
 */
function reder_quan_huyen_option($tinh_thanh, $default) {
  $default    = sprintf('%02d', intval($default));
  $tinh_thanh = sprintf('%02d', intval($tinh_thanh));
  $json_file  = get_stylesheet_directory() . "/json/quan-huyen/" . $tinh_thanh . ".json";
  if (file_exists($json_file)) {
    $json       = file_get_contents($json_file);
    $quan_huyen = json_decode($json, true);
    foreach ($quan_huyen as $key => $value) {
      if ($key == $default) {
        $select = "selected";
      } else {
        $select = "";
      }
      echo "<option " . $select . " value='" . $key . "'>" . $value["name_with_type"] . "</option>";
    }
  }
}
/**
 * @return HTML - option list xã phường
 */
function reder_xa_phuong_option($quan_huyen, $default) {
  $default    = intval($default);
  $quan_huyen = sprintf('%03d', intval($quan_huyen));
  $json_file  = get_stylesheet_directory() . "/json/xa-phuong/" . $quan_huyen . ".json";
  if (file_exists($json_file)) {
    $json      = file_get_contents($json_file);
    $xa_phuong = json_decode($json, true);
    foreach ($xa_phuong as $key => $value) {
      if ($key == $default) {$select = "selected";} else { $select = "";}
      echo "<option " . $select . " value='" . $key . "'>" . $value["name_with_type"] . "</option>";
    }
  }
}
/**
 * AJAX load quận huyện khi select tỉnh thành phố
 */
add_action('wp_ajax_load_quan_huyen', 'load_quan_huyen');
function load_quan_huyen() {
  $tinh_thanh = $_POST['id'];
  $type       = $_POST['type'];
  $json_file  = get_stylesheet_directory() . "/json/quan-huyen/" . $tinh_thanh . ".json";
  if (file_exists($json_file)) {
    $json       = file_get_contents($json_file);
    $quan_huyen = json_decode($json, true);
    echo '<option value="" disabled selected >' . __("Select", "golf") . '</option>';
    foreach ($quan_huyen as $key => $value) {
      if ($type) {
        echo "<option value='" . $value["name_with_type"] . "'>" . $value["name_with_type"] . "</option>";
      } else {
        echo "<option value='" . $key . "'>" . $value["name_with_type"] . "</option>";
      }
    }
  }
  die();
}
/**
 * AJAX load danh sách xã phường khi select tỉnh thành phố
 */
add_action('wp_ajax_load_xa_phuong', 'load_xa_phuong');
function load_xa_phuong() {
  $quan_huyen = $_POST['id'];
  $json_file  = get_stylesheet_directory() . "/json/xa-phuong/" . $quan_huyen . ".json";
  if (file_exists($json_file)) {
    $json      = file_get_contents($json_file);
    $xa_phuong = json_decode($json, true);
    foreach ($xa_phuong as $key => $value) {
      echo "<option value='" . $key . "'>" . $value["name_with_type"] . "</option>";
    }
  }
  die();
}
/**
 *
 * Get địa chỉ của user bởi id
 * Nếu chưa update địa chỉ, thì gán mặc định là: '90 Đường Lê Lợi, Phường Bến Thành, Quận 1, Thành phố Hồ Chí Minh'
 */
function get_address_by_id_user($user_id = null) {
  if (!$user_id) {
    $user_id = get_current_user_id();
  }
  $province_address = get_user_meta($user_id, "province_address", true);
  if ($province_address) {
    return json_decode($province_address, true);
  }
  return array(
    'province' => 79,
    'district' => 760,
    'ward'     => 26743,
    'street'   => '90 Đường Lê Lợi',
  );
}
/**
 * Get địa chỉ text
 * @return array
 */
function atw_load_province_address($user_id = null) {
  $province = '';
  $district = '';
  $ward     = '';
  if (!$user_id) {
    $user_id = get_current_user_id();
  }
  $province_address = get_address_by_id_user($user_id);
  if ($province_address && is_array($province_address)) {
    $json_file = get_stylesheet_directory() . "/json/tinh_tp.json";
    if (file_exists($json_file)) {
      $json_tinh_tp = file_get_contents($json_file);
      $tinh_thanh   = json_decode($json_tinh_tp, true);
      foreach ($tinh_thanh as $key => $value) {
        if ($key == $province_address['province']) {
          $province = $tinh_thanh[$key]['name'];
          break;
        }
      }
    }
    if ($province_address['province']):
      $json_file = get_stylesheet_directory() . "/json/quan-huyen/" . $province_address['province'] . ".json";
      if (file_exists($json_file)) {
        $json_quan_huyen = file_get_contents($json_file);
        $quan_huyen      = json_decode($json_quan_huyen, true);
        foreach ($quan_huyen as $key => $value) {
          if ($key == $province_address['district']) {
            $district = $quan_huyen[$key]['name_with_type'];
            break;
          }
        }
      }
    endif;
    if ($province_address['district']):
      $json_file = get_stylesheet_directory() . "/json/xa-phuong/" . $province_address['district'] . ".json";
      if (file_exists($json_file)) {
        $json_xa_phuong = file_get_contents($json_file);
        $xa_phuong      = json_decode($json_xa_phuong, true);
        foreach ($xa_phuong as $key => $value) {
          if ($key == $province_address['ward']) {
            $ward = $xa_phuong[$key]['name_with_type'];
            break;
          }
        }
      }
    endif;
  }
  return array(
    'province' => $province,
    'district' => $district,
    'ward'     => $ward,
    'street'   => $province_address['street'],
  );
}
/**
 *
 * Crop image
 */
function resize_image($method, $image_loc, $new_loc, $width, $height) {
  $exif = exif_read_data($image_loc);
  if (isset($exif['Orientation']) && $exif['Orientation'] === 6) {
    $rotate = -90;
  } else if (isset($exif['Orientation']) && $exif['Orientation'] === 3) {
    $rotate = 180;
  } else if (isset($exif['Orientation']) && $exif['Orientation'] === 8) {
    $rotate = 90;
  }
  if (!is_array(@$GLOBALS['errors'])) {$GLOBALS['errors'] = array();}
  if (!in_array($method, array('force', 'max', 'crop'))) {$GLOBALS['errors'][] = 'Invalid method selected.';}
  if (!$image_loc) {$GLOBALS['errors'][] = 'No source image location specified.';} else {
    if ((substr(strtolower($image_loc), 0, 7) == 'http://') || (substr(strtolower($image_loc), 0, 7) == 'https://')) { /*don't check to see if file exists since it's not local*/} elseif (!file_exists($image_loc)) {$GLOBALS['errors'][] = 'Image source file does not exist.';}
    $extension = strtolower(substr($image_loc, strrpos($image_loc, '.')));
    if (!in_array($extension, array('.jpg', '.jpeg', '.png', '.gif', '.bmp'))) {$GLOBALS['errors'][] = 'Invalid source file extension!';}
  }
  if (!$new_loc) {$GLOBALS['errors'][] = 'No destination image location specified.';} else {
    $new_extension = strtolower(substr($new_loc, strrpos($new_loc, '.')));
    if (!in_array($new_extension, array('.jpg', '.jpeg', '.png', '.gif', '.bmp'))) {$GLOBALS['errors'][] = 'Invalid destination file extension!';}
  }
  $width = abs(intval($width));
  if (!$width) {$GLOBALS['errors'][] = 'No width specified!';}
  $height = abs(intval($height));
  if (!$height) {$GLOBALS['errors'][] = 'No height specified!';}
  if (count($GLOBALS['errors']) > 0) {echo_errors();return false;}
  if (in_array($extension, array('.jpg', '.jpeg'))) {$image = @imagecreatefromjpeg($image_loc);} elseif ($extension == '.png') {$image = @imagecreatefrompng($image_loc);} elseif ($extension == '.gif') {$image = @imagecreatefromgif($image_loc);} elseif ($extension == '.bmp') {$image = @imagecreatefromwbmp($image_loc);}
  if (!$image) {$GLOBALS['errors'][] = 'Image could not be generated!';} else {
    $current_width  = imagesx($image);
    $current_height = imagesy($image);
    if ((!$current_width) || (!$current_height)) {$GLOBALS['errors'][] = 'Generated image has invalid dimensions!';}
  }
  if (count($GLOBALS['errors']) > 0) {
    @imagedestroy($image);
    echo_errors();return false;}
  if ($method == 'force') {$new_image = resize_image_force($image, $width, $height);} elseif ($method == 'max') {$new_image = resize_image_max($image, $width, $height);} elseif ($method == 'crop') {$new_image = resize_image_crop($image, $width, $height);}
  if ((!$new_image) && (count($GLOBALS['errors'] == 0))) {$GLOBALS['errors'][] = 'New image could not be generated!';}
  if (count($GLOBALS['errors']) > 0) {
    @imagedestroy($image);
    echo_errors();return false;}
  $save_error = false;
  if (in_array($extension, array('.jpg', '.jpeg'))) {
    if (isset($rotate)) {$new_image = imagerotate($new_image, $rotate, 0);}
    imagejpeg($new_image, $new_loc) or ($save_error = true);} elseif ($extension == '.png') {
    if (isset($rotate)) {$new_image = imagerotate($new_image, $rotate, 0);}
    imagepng($new_image, $new_loc) or ($save_error = true);} elseif ($extension == '.gif') {imagegif($new_image, $new_loc) or ($save_error = true);} elseif ($extension == '.bmp') {imagewbmp($new_image, $new_loc) or ($save_error = true);}
  if ($save_error) {$GLOBALS['errors'][] = 'New image could not be saved!';}
  if (count($GLOBALS['errors']) > 0) {
    @imagedestroy($image);@imagedestroy($new_image);
    echo_errors();return false;}
  imagedestroy($image);
  imagedestroy($new_image);
  return true;
}
function echo_errors() {
  if (!is_array(@$GLOBALS['errors'])) {$GLOBALS['errors'] = array('Unknown error!');}
  foreach ($GLOBALS['errors'] as $error) {echo '<p style="color:red;font-weight:bold;">Error: ' . $error . '</p>';}
}
function resize_image_force($image, $width, $height) {
  $w = @imagesx($image); //current width
  $h = @imagesy($image); //current height
  if ((!$w) || (!$h)) {$GLOBALS['errors'][] = 'Image couldn\'t be resized because it wasn\'t a valid image.';return false;}
  if (($w == $width) && ($h == $height)) {return $image;} //no resizing needed
  $image2 = imagecreatetruecolor($width, $height);
  imagecopyresampled($image2, $image, 0, 0, 0, 0, $width, $height, $w, $h);
  return $image2;
}
function resize_image_max($image, $max_width, $max_height) {
  $w = imagesx($image); //current width
  $h = imagesy($image); //current height
  if ((!$w) || (!$h)) {$GLOBALS['errors'][] = 'Image couldn\'t be resized because it wasn\'t a valid image.';return false;}
  if (($w <= $max_width) && ($h <= $max_height)) {return $image;} //no resizing needed
  //try max width first...
  $ratio = $max_width / $w;
  $new_w = $max_width;
  $new_h = $h * $ratio;
  //if that didn't work
  if ($new_h > $max_height) {
    $ratio = $max_height / $h;
    $new_h = $max_height;
    $new_w = $w * $ratio;
  }
  $new_image = imagecreatetruecolor($new_w, $new_h);
  imagecopyresampled($new_image, $image, 0, 0, 0, 0, $new_w, $new_h, $w, $h);
  return $new_image;
}
function resize_image_crop($image, $width, $height) {
  $w = @imagesx($image); //current width
  $h = @imagesy($image); //current height
  if ((!$w) || (!$h)) {$GLOBALS['errors'][] = 'Image couldn\'t be resized because it wasn\'t a valid image.';return false;}
  if (($w == $width) && ($h == $height)) {return $image;} //no resizing needed
  //try max width first...
  $ratio = $width / $w;
  $new_w = $width;
  $new_h = $h * $ratio;
  //if that created an image smaller than what we wanted, try the other way
  if ($new_h < $height) {
    $ratio = $height / $h;
    $new_h = $height;
    $new_w = $w * $ratio;
  }
  $image2 = imagecreatetruecolor($new_w, $new_h);
  imagecopyresampled($image2, $image, 0, 0, 0, 0, $new_w, $new_h, $w, $h);
  //check to see if cropping needs to happen
  if (($new_h != $height) || ($new_w != $width)) {
    $image3 = imagecreatetruecolor($width, $height);
    if ($new_h > $height) {
      //crop vertically
      $extra = $new_h - $height;
      $x     = 0; //source x
      $y     = round($extra / 2); //source y
      imagecopyresampled($image3, $image2, 0, 0, $x, $y, $width, $height, $width, $height);
    } else {
      $extra = $new_w - $width;
      $x     = round($extra / 2); //source x
      $y     = 0; //source y
      imagecopyresampled($image3, $image2, 0, 0, $x, $y, $width, $height, $width, $height);
    }
    imagedestroy($image2);
    return $image3;
  } else {
    return $image2;
  }
}
function upload_image($file) {
  $targetDir      = wp_upload_dir()["basedir"] . '/image-files/';
  $allowTypes     = array('jpg', 'png', 'jpeg');
  $fileName       = round(microtime(true)) . "_" . basename($file['name']);
  $targetFilePath = $targetDir . $fileName;
  // Check whether file type is valid
  $fileType = pathinfo($targetFilePath, PATHINFO_EXTENSION);
  if (in_array($fileType, $allowTypes)) {
    if ($file["size"] > 10000000) {
      return array("status" => "error", "content" => "Maximum 10Mb");
    }
    if (move_uploaded_file($file['tmp_name'], $targetFilePath)) {
      resize_image('crop', $targetDir . $fileName, $targetDir . '200x200/' . $fileName, 200, 200);
      $file_id = umm_model_insert_img($fileName);
      return array("status" => "success", "content" => $file_id);
    }
  } else {
    return array("status" => "error", "content" => "Allow jpg, png, jpeg");
  }
}
function umm_model_insert_img($file_name) {
  global $wpdb;
  $table  = $wpdb->prefix . 'images';
  $data   = array('image_name' => $file_name, 'user_id' => get_current_user_id());
  $format = array('%s', '%d');
  $wpdb->insert($table, $data, $format);
  return $wpdb->insert_id;
}
function get_image_url_by_id($id, $size = "full") {
  $url = wp_get_upload_dir()["baseurl"] . "/image-files/";
  if ($size != "full") {
    $url = wp_get_upload_dir()["baseurl"] . "/image-files/200x200/";
  }
  global $wpdb;
  $table  = $wpdb->prefix . "images";
  $result = $wpdb->get_results($wpdb->prepare(" SELECT image_name  FROM  {$table} WHERE id = %d ", $id), ARRAY_A, 1);
  return $url . $result[0]["image_name"];
}
/**
 *
 * Delete uploaded images file, database
 */
function delete_img_by_id($img_id) {
  global $wpdb;
  $table     = $wpdb->prefix . "images";
  $result    = $wpdb->get_results($wpdb->prepare(" SELECT image_name  FROM  {$table} WHERE id = %d ", $img_id), ARRAY_A, 1);
  $file_name = $result[0]["image_name"];
  $folder    = wp_upload_dir()["basedir"] . '/image-files/';
  unlink($folder . $file_name);
  unlink($folder . "200x200/" . $file_name);
  $wpdb->delete($table, array('id' => $img_id), array('%d'));
}
/**
 *
 * Get image url avatar  by user id
 */
function get_url_avatar($user_id = '') {
  if ($user_id === '') {
    $user_id = get_current_user_id();
  }
  $id_avatar = get_user_meta($user_id, 'id_img_avatar', true);
  if ($id_avatar) {
    return get_image_url_by_id($id_avatar, 'thumbnail');
  }
  return AVATAR_DF;
}
/**
 *
 * Check user exists
 * @return boolean
 */
function is_user_exist($user_id) {
  $user       = get_userdata($user_id);
  $user_roles = !empty($user) ? $user->roles[0] : "";
  if ($user === false or $user_roles != USER) {
    return false;
  } else {
    return true;
  }
}
/**
 *
 * Check View other account
 * @return boolean
 */
function is_view_other_account() {
  if (is_page('account') && isset($_GET['id']) && intval($_GET['id']) !== get_current_user_id()) {
    return true;
  }
  return false;
}
/**
 *
 * Get list user follow
 * @return array
 */
function list_user_follow($user_id = null) {
  if (!$user_id) {
    $user_id = get_current_user_id();
  }
  $list_user_follow = get_user_meta($user_id, 'list_user_follow', true);
  if (!$list_user_follow) {
    return array();
  }
  return json_decode($list_user_follow, true);
}
/**
 *
 * Nhận danh sách người theo dõi tôi
 * @return array
 */
function get_list_follower($current_user_id = null) {
  if (!$current_user_id) {
    $current_user_id = get_current_user_id();
  }
  $args              = array('role' => USER);
  $users             = get_users($args);
  $list_follower_arr = [];
  foreach ($users as $value) {
    $user_id         = $value->ID;
    $list_follow_arr = list_user_follow($user_id);
    if ($list_follow_arr):
      if (in_array($current_user_id, $list_follow_arr)) {
        $list_follower_arr[] = $user_id;
      }
    endif;
  }
  return $list_follower_arr;
}
/**
 *
 * Nhận tổng số người tôi đang theo dõi
 * @return int
 */
function get_total_following($current_user_id = null) {
  if (!$current_user_id) {
    $current_user_id = get_current_user_id();
  }
  return count(list_user_follow($current_user_id));
}
/**
 * tăng lên 1 so tổng thông báo mới hiện tại của user ID
 */
function update_total_notify_user($user_id){
  $total = (int)get_user_meta( $user_id, 'total_notify', true ) + 1;
  update_user_meta( $user_id, 'total_notify', $total);
}

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\js\frontend.js

function replaceUrlParam(url, paramName, paramValue) {
  var href = new URL(url);
  href.searchParams.set(paramName, paramValue);
  return href.toString();
}
jQuery(document).ready(function($) {
  $('.menu-tab .tab-a').click(function(e) {
    e.preventDefault();
    $('.menu-tab li').removeClass('active')
    $(".tab").removeClass('tab-active');
    $(".tab[data-tab-id='" + $(this).attr('data-id') + "']").addClass("tab-active");
    $(".tab-a").removeClass('active');
    $(this).parent().addClass('active');
  });
  $('body').on('click', '.show-hiden', function(e) {
    const isInput = $(this).prev();
    const typeAttr = isInput.attr("type");
    if (typeAttr == 'password') {
      isInput.attr("type", "text");
      $(this).text('Hidden');
    } else {
      isInput.attr("type", "password");
      $(this).text('Show');
    }
  });
  // Load danh sách tỉnh thành
  $("body").on("change", ".province-select", function(e) {
    $(".ward-select").html("");
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'load_quan_huyen',
        id: $(this).val(),
      },
      beforeSend: function() {
        $(".district-select").prop("disabled", true);
      },
      success: function(output) {
        $(".district-select").html(output);
        $(".district-select").prop("disabled", false);
      },
    });
  });
  // Load danh sách xã phường
  $("body").on("change", ".district-select", function() {
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'load_xa_phuong',
        id: $(this).val(),
      },
      beforeSend: function() {
        $(".ward-select").prop("disabled", true);
      },
      success: function(output) {
        $(".ward-select").html(output);
        $(".ward-select").prop("disabled", false);
      },
    });
  });
  // Preview avatar upload
  const inputImg = $('input#image-avatar')
  const imgPreview = $('#preview-img')
  $('body').on('click', '.btn-upload', (e) => {
    inputImg.click();
  })
  $('.box-preview-img').on('change', inputImg, function(e) {
    const file = e.target.files[0]
    const reader = new FileReader();
    reader.onload = function(e) {
      imgPreview.attr('src', e.target.result);
    }
    reader.readAsDataURL(file);
  })
  // add follow
  $('body').on('click', 'button.btn-follow__add', function(e) {
    e.preventDefault();
    const $this = $(this);
    const user_id = $this.data('id');
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'app_add_follow',
        token: $('#nonce_token').val(),
        id: user_id,
      },
      beforeSend: function() {
        $this.addClass('loading');
      },
      success: function(response) {
        $this.removeClass('loading')
        if (response == true) {
          $this.text(app.unfollow);
          $this.removeClass('btn-follow__add');
          $this.addClass('btn-follow__remove');
        }
      },
      error: function() {
        $this.removeClass('loading');
        alert('Error');
      }
    });
  });
  // Unfollow
  $('body').on('click', 'button.btn-follow__remove', function(e) {
    e.preventDefault();
    const $this = $(this);
    const user_id = $this.data('id');
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'app_un_follow',
        token: $('#nonce_token').val(),
        id: user_id,
      },
      beforeSend: function() {
        $this.addClass('loading');
      },
      success: function(response) {
        $this.removeClass('loading')
        if (response == true) {
          $this.text(app.follow);
          $this.removeClass('btn-follow__remove');
          $this.addClass('btn-follow__add');
        }
      },
      error: function() {
        $this.removeClass('loading');
        alert('Error');
      }
    });
  });
  $("body").on("click", "a.posts__item__like", function(e) {
    var $this = $(this);
    e.preventDefault();
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'like_post',
        token: $(this).data("token"),
        post_id: $(this).data("post-id"),
        author: $(this).data("author"),
      },
      beforeSend: function() {
        $this.addClass('no-click');
      },
      success: function(response) {
        $this.removeClass('posts__item__like');
        $this.addClass('posts__item__dislike');
        $this.removeClass('no-click');
        $this.find('.posts__item__like__count').text(response);
      },
      error: function() {
        alert('error');
      }
    });
  });
  $("body").on("click", "a.posts__item__dislike", function(e) {
    var $this = $(this);
    e.preventDefault();
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'dislike_post',
        token: $(this).data("token"),
        post_id: $(this).data("post-id"),
        author: $(this).data("author"),
      },
      beforeSend: function() {
        $this.addClass('no-click');
      },
      success: function(response) {
        $this.removeClass('posts__item__dislike');
        $this.addClass('posts__item__like');
        $this.removeClass('no-click');
        $this.find('.posts__item__like__count').text(response);
      },
      error: function() {
        alert('error');
      }
    });
  });
  // Join Group
  $("body").on("click", ".btn-join", function(e) {
    e.preventDefault();
    const $this = $(this);
    const type = $this.data("type");
    const group_id = $this.data('id');
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'join_group',
        token: $('#nonce_token').val(),
        group_id: group_id,
      },
      beforeSend: function() {
        $this.addClass('loading');
      },
      success: function(response) {
        $this.removeClass('loading');
        if (response == 'success') {
          $this.addClass('disabled');
          if (type == 'view_group') {
            let currURL = window.location.href;
            currURL = currURL.split('?')[0];
            currURL = currURL + "?action=view-group&id=" + group_id + "&appt=C";
            window.location.replace(currURL);
          }
        }
      },
      error: function() {
        $this.removeClass('loading');
        alert('error');
      }
    });
  });
  // search user join group
  $("#search-user-invite").keyup(function() {
    const keyWord = $(this).val();
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'search_user_invite_join_group',
        keyword: keyWord,
        group_id: $('#group_id_invite').val(),
        token: $('#nonce_token').val(),
      },
      beforeSend: function() {},
      success: function(output) {
        //console.log(output);
        $('.box-user-invite__list').html(output);
      },
      error: function() { alert('error'); }
    });
  });
  // button invite user join group
  $("body").on("click", ".box-user-invite__item__button", function(e) {
    const $this = $(this);
    const idUser = $this.data('id');
    $.ajax({
      url: app.ajaxUrl,
      type: "post",
      dataType: "text",
      data: {
        action: 'invite_user_join_group',
        user_id: idUser,
        group_id: $('#group_id_invite').val(),
        token: $('#nonce_token').val(),
      },
      beforeSend: function() {
        $this.addClass('loading');
      },
      success: function(output) {
        console.log(output);
        $this.removeClass('loading');
        $this.attr("disabled", true);
        if (output == 'success') {
          $this.text(app.sent);
        }
      },
      error: function() {
        $this.removeClass('loading');
        alert('error');
      }
    });
  })
});
// add multiple images delete option
jQuery(document).ready(function($) {
  var xp = 0;
  var input_btn = 0;
  var dts = [];
  var l = $(".at-gr-input-file"),
    t = $(".form-group.list_attach");
  function cl() {
    $(".form-group", l).length <= 5 && 0 <= $(".form-group", l).length ? t.addClass("show-btn") : t.removeClass("show-btn");
  }
  $(document).on("click", ".at-add-image-btn", function(e) {
    //cl();
    let leg_current = $(".at-gr-input-file .at-form-group").length;
    if (leg_current >= 6) {
      alert("Maximum 6 images");
      return;
    } else {
      input_btn++;
      $(".list_input").append(
        "<input type='file' style='display:none;' name='upload_files[]' id='filenumber" +
        input_btn +
        "' class='img_file upload_files' accept='.gif,.jpg,.jpeg,.png,' multiple/>"
      );
      $("#filenumber" + input_btn).click();
    }
  });
  $(document).on("change", ".upload_files", function(e) {
    $('.btn-upload').addClass('hidden');
    let leg_current = $(".at-gr-input-file .at-form-group").length;
    files = e.target.files;
    filesLength = files.length;
    if (filesLength + leg_current >= 7) {
      alert("Maximum 6 images");
      return
    }
    for (var i = 0; i < filesLength; i++) {
      xp++;
      var f = files[i];
      var res_ext = files[i].name.split(".");
      var img_or_video = res_ext[res_ext.length - 1];
      var fileReader = new FileReader();
      fileReader.name = f.name;
      fileReader.onload = function(e) {
        var file = e.target;
        $(".at-gr-input-file").append(
          "<div class='at-form-group at-form-group" +
          xp +
          "'><i deltsid='" + 0 + "' data-title='" + file.name + "' class='cancel_mutile_image fa fa-times at-remove-input' title='Remove' aria-hidden='true'><svg width='40' height='41'><use href='#icon-close'></use></svg></i><div class='at_item_image background_v" +
          xp +
          "' style='background-image: url(" +
          e.target.result +
          ")'></div></div>"
        );
      };
      fileReader.readAsDataURL(f);
    }
  });
  var rty = 0;
  $(document).on("click", ".cancel_mutile_image.at-remove-input", function(e) {
    $('.cancel_mutile_image').each(function() {
      chk_id = $(this).attr('deltsid');
      if (chk_id == 0) {
        rty++;
        $(this).attr('deltsid', rty);
      }
    });
    //deltsid = $(this).attr('data-title');
    deltsid = $(this).attr('deltsid');
    dts.push(deltsid);
    $(this).closest(".at-form-group").remove();
    $('#remove_image_title').val(dts);
    //cl();
  });
  // delete image update post
  var arr_img_delete = [];
  $(".single").on("click", ".remove-img", function(e) {
    var data_id = $(this).data('id-img');
    arr_img_delete.push(data_id);
    $(this).parent(".at-form-group").remove();
    $('#remove_image').val(arr_img_delete);
  });
});

UnFollow

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\ajax\account.php

<?php
/**
 * App Update Info
 */
add_action('wp_ajax_app_update_info', 'app_update_info');
function app_update_info() {
  check_ajax_referer(AT_NONCE_KEY . 'update-info', 'update-info-token');
  $status   = false;
  $message  = '';
  $username = sanitize_text_field($_POST['username']);
  $phone    = sanitize_text_field($_POST['phone']);
  $email    = sanitize_text_field($_POST['email']);
  $language = sanitize_text_field($_POST['language']);
  $province = intval($_POST['province']);
  $district = intval($_POST['district']);
  $ward     = intval($_POST['ward']);
  $street   = sanitize_text_field($_POST['street']);
  global $current_user;
  $current_email            = $current_user->user_email;
  $current_user_id          = $current_user->ID;
  $data_user_for_update_arr = array(
    'ID'           => $current_user_id,
    'display_name' => $username,
  );
  $province_address = array(
    'province' => $province,
    'district' => $district,
    'ward'     => $ward,
    'street'   => $street,
  );
  $province_address = json_encode($province_address, JSON_UNESCAPED_UNICODE);
  if ($current_email != $email) {
    if (email_exists($email)) {
      $status  = true;
      $message = __("Email already exists", "umm");
    } elseif (!is_email($email)) {
      $status  = true;
      $message = __("Invalid email", "umm");
    } else {
      $data_user_for_update_arr["user_email"] = $email;
    }
  }
  if (!$status) {
    wp_update_user($data_user_for_update_arr);
    update_user_meta($current_user_id, 'user_phone', $phone);
    update_user_meta($current_user_id, 'language', $language);
    update_user_meta($current_user_id, "province_address", $province_address);
  }
  if (isset($_FILES["image-avarta"]) && !empty($_FILES['image-avarta']['name'])) {
    $result_upload = upload_image($_FILES["image-avarta"]);
    if ($result_upload['status'] == 'success') {
      $id_avatar_curr = get_user_meta($current_user_id, 'id_img_avatar', true);
      if ($id_avatar_curr) {
        delete_img_by_id($id_avatar_curr);
      }
      update_user_meta($current_user_id, 'id_img_avatar', $result_upload['content']);
    } else {
      $message = __("upload error ", "umm");
      $status  = true;
    }
  }
  echo json_encode(array(
    'status'  => $status,
    'message' => $message)
  );
  die();
}
/**
 * Add Follow
 */
add_action('wp_ajax_app_add_follow', 'app_add_follow');
function app_add_follow() {
  $current_user_id = get_current_user_id();
  if (!isset($_POST['token']) || !wp_verify_nonce($_POST['token'], AT_NONCE_KEY . 'ajax-nonce' . $current_user_id)) {
    die("error verify");
  }
  $user_id = intval($_POST["id"]);
  $list_user_follow = get_user_meta($current_user_id, 'list_user_follow', true);
  if ($list_user_follow) {
    $list_user_follow_arr = json_decode($list_user_follow, true);
    if (is_array($list_user_follow_arr)) {
      $list_user_follow_arr[] = $user_id;
    }
  } else {
    $list_user_follow_arr = array($user_id);
  }
  $list_user_follow_arr = array_unique($list_user_follow_arr); 
  $result               = update_user_meta($current_user_id, 'list_user_follow', json_encode($list_user_follow_arr));
  if ($result) {
    global $bj_controller;
    $model = $bj_controller->Model("notification");
    $id    = $model->create_notification(
      array(
        "from"    => $current_user_id,
        "to"      => $user_id,
        "type"    => "has_follow",
        "content" => '',
      )
    );
    if ($id) {
      update_total_notify_user($user_id);
    }
    echo true;
  }
  die();
}
/**
 * Un Follow
 */
add_action('wp_ajax_app_un_follow', 'app_un_follow');
function app_un_follow() {
  $current_user_id = get_current_user_id();
  if (!isset($_POST['token']) || !wp_verify_nonce($_POST['token'], AT_NONCE_KEY . 'ajax-nonce' . $current_user_id)) {
    die("error verify");
  }
  $user_id = intval($_POST["id"]);
  $list_user_follow_arr = list_user_follow();
  if (($key = array_search($user_id, $list_user_follow_arr)) !== false) {
    unset($list_user_follow_arr[$key]);
    global $bj_controller;
    $model  = $bj_controller->Model("notification");
    $result = $model->del_notification_exact(
      array(
        "from"    => $current_user_id,
        "to"      => $user_id,
        "type"    => "has_follow",
        "content" => '',
      )
    );
  }
  $result = update_user_meta($current_user_id, 'list_user_follow', json_encode($list_user_follow_arr));
  if ($result) {
    echo true;
  }
  die();
}

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\models\notification.php

<?php
class BJ_notification_Model extends Pv_Controller {
  private $table_notification_name = 'notification';
  public function create_notification($input) {
    global $wpdb;
    $table = $wpdb->prefix . $this->table_notification_name;
    $data  = array(
      "from_"   => $input["from"],
      "to_"     => $input["to"],
      "type"    => $input["type"],
      "content" => $input["content"],
    );
    $format = array('%d', '%d', '%s', '%s');
    $wpdb->insert($table, $data, $format);
    return $wpdb->insert_id;
  }
  public function del_notification_exact($input) {
    global $wpdb;
    $table  = $wpdb->prefix . $this->table_notification_name;
    $result = $wpdb->delete($table, array(
      "from_"   => $input["from"],
      "to_"     => $input["to"],
      "type"    => $input["type"],
      "content" => $input["content"],
    ), array('%d', '%s', '%s', '%s'));
    return $result;
  }
}

Page http://localhost/reset4/account/?action=followers

Page http://localhost/reset4/account/?action=following

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\controllers\Account.php

<?php
class BJ_Account_Controller extends Pv_Controller {
  function __construct() {
    if (isset($_GET['action'])):
      switch ($_GET['action']) {
      case "edit-info":
        $this->update_info();
        break;
      case "followers":
        $this->followers();
        break;
      case "following":
        $this->following();
        break;
      default:
        $this->index();
      } else :
      $this->index();
    endif;
  }
  private function get_user_id() {
    if (isset($_GET["id"]) && is_user_exist(strip_tags($_GET["id"]))) {
      return $_GET["id"];
    } else {
      return get_current_user_id();
    }
  }
  public function index() {
    $data                         = array();
    $user_id                      = $this->get_user_id();
    $user_obj                     = get_userdata($user_id);
    $data['id']                   = $user_id;
    $data['display_name']         = $user_obj->display_name;
    $data['date_registered']      = date_i18n(__('jS F Y', 'umm'), strtotime($user_obj->user_registered));
    $data['avatar']               = get_url_avatar($user_id);
    $data['province_address_arr'] = atw_load_province_address($user_id);
    $this->load()->View("account", $data, "account");
  }
  public function update_info() {
    $data = array();
    $this->load()->View("update-info", $data, "account");
  }
  public function followers() {
    $current_user_id       = $this->get_user_id();
    $data                  = array();
    $data['list_follower'] = get_list_follower($current_user_id);
    $this->load()->View("followers", $data, "account");
  }
  public function following() {
    $user_id             = $this->get_user_id();
    $data                = array();
    $data['list_follow'] = list_user_follow($user_id);
    $this->load()->View("following", $data, "account");
  }
}

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\views\account\followers.php

<div class="page-followers container">
  <div class="list-follower mt-4">
  <?php if( $args['list_follower'] && is_array($args['list_follower']) ): ?>
    <?php
    foreach($args['list_follower'] as $user_id){
      $user_obj = get_userdata( $user_id );
      $avatar_img = get_url_avatar($user_id);
      $link_account = SITE_URL . "account/?id={$user_id}&appt=N";
      $display_name = $user_obj->display_name;
      $class = 'btn-follow__remove';
      $btn_text = __('Unfollow', 'umm');
      if ( !is_user_exist($user_id) ) continue;
      if(  !in_array( $user_id, list_user_follow() ) ) {
        $class = 'btn-follow__add';
        $btn_text = __('Follow', 'umm');
      }
      if ( $user_id == get_current_user_id() ){
        $class .= ' no-click';
      }
      ?>
      <div class="list-follower__item d-flex align-items-center justify-content-between border-b-1 py-2">
        <div class="list-follower__item__avatar">
          <a href="<?php echo $link_account ?>" class="d-block">
            <img src="<?php echo $avatar_img ?>" class="rounded-circle" width="60" height="60">
          </a>
        </div>
        <div class="list-follower__item__name flex-fill ml-4">
          <a href="<?php echo $link_account ?>"><?php echo $display_name; ?></a>
        </div>
        <button type="button" data-id="<?php echo $user_id; ?>" class="<?php echo $class ?> list-follower__item__button btn bg-primary text-white font-weight-600"> <?php echo $btn_text; ?> 
        </button>
      </div>
    <?php } ?>
  <?php endif; ?>
  </div>
</div>

C:\xampp\htdocs\reset4\wp-content\themes\addframwork\framework\views\account\following.php

<div class="page-following container">
  <div class="list-follower mt-4">
    <?php if( $args['list_follow'] && is_array($args['list_follow']) ): ?>
    <?php
    foreach($args['list_follow'] as $user_id){
      if ( !is_user_exist($user_id) ) continue;
      $class = '';
      if ( $user_id == get_current_user_id() ){
        $class = 'no-click';
      }
      $user_obj = get_userdata( $user_id );
      $avatar_img = get_url_avatar($user_id);
      $link_account = SITE_URL . "account?id={$user_id}&appt=N";
      $display_name = $user_obj->display_name;
    ?>
    <div class="list-follower__item d-flex align-items-center justify-content-between border-b-1 py-2">
      <div class="list-follower__item__avatar">
        <a href="<?php echo $link_account ?>" class="d-block">
          <img src="<?php echo $avatar_img ?>" class="rounded-circle" width="60" height="60">
        </a>
      </div>
      <div class="list-follower__item__name flex-fill ml-4">
        <a href="<?php echo $link_account ?>">
          <?php echo $display_name; ?></a>
      </div>
      <button type="button" data-id="<?php echo $user_id; ?>" class="<?php echo $class ?> list-follower__item__button btn btn-follow__remove bg-primary text-white font-weight-600">
        <?php _e('Unfollow', 'umm'); ?>
      </button>
    </div>
    <?php } ?>
    <?php endif; ?>
  </div>
</div>

Last updated