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

## **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 */;
```

![](/files/N07I5fNDGJtWHozD5qJo)

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**

![](/files/fQBgTwg5XBJmpmpatDJi)

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;
  }
}
```

![](/files/Rlge8kdsTBcD8eE4KS2E)

**Page** [**http://localhost/reset4/account/?action=followers**](http://localhost/reset4/account/?action=followers)

![](/files/AmXcFbue9cIlZH1zjpyt)

**Page** [**http://localhost/reset4/account/?action=following**](http://localhost/reset4/account/?action=following)

![](/files/QtA2alW6VS98ywURwa3K)

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>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://learnphp.gitbook.io/learnphp/wordpress-advand/framework-xay-dung-page-account-phan-2-ok.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
