Boostrap Modal Contents를 Dynamic하게 Load하기

Share on facebook
Facebook
Share on twitter
Twitter
Share on linkedin
LinkedIn
Share on print
Print

1. WordPress Header에 여러 개의 Modal을 사용할 때 문제점

Bootstrap Modal을 사용하여 Login / Register 창을 만들었다. 각각별로 별도 Modal을 사용하였고, 처음 Login 버튼을 누르는 경우 ① Login Modal이 나타나고, Login Modal 아래 링크를 누르는 경우 ② Regsiter Modal이 나타나도록 구현하였다.

문제는 이용약관과 개인정보수집동의도 버튼 클릭 시에 ③ Service Term Modal과 ④ Privacy Modal로 나타나도록 구현해놓고 보니, 최종적으로 php가 출력한 html이 아래처럼 길게 나왔다는 거다.

이 코드가 출력하는 부분이 wordpress의 header에 해당하기 때문에, 이 기다란 코드가 웹사이트의 모든 HTML 코드에 출력되는 말도 안되는 모양이 되어버렸다.

글을 계속하기 전에, 굉장히 길고 긴 문서이므로 최종적으로 만드려고 하는 결과를 먼저 보자.


<div class="login-button">
  <a class="my-login" data-toggle="modal" data-target="#myModal" href="#">Login</a>   
</div>

<!-- modal#1 로그인 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="myModalLabel">로그인</h4>
      </div>
      <div class="modal-body">
        <form id="login" action="" method="post"> <!-- 필요한 action 지정 -->
          <div class="login-error alert alert-danger" role="alert" style="display: none;"></div>
          <input type="email" id="login_email" name="email" class="form-control" autocomplete="username" placeholder="e-mail을 적어주세요"> 
          <input type="password" id="login_password" name="password" class="form-control" autocomplete="current-password" placeholder="비밀번호">
          <input type="checkbox" id="remember" name="remember"><label for="cbox2">기억하기</label>
          <button type="submit" class="btn btn-primary submit_button">로그인</button>
          <div class="lost-pass"><a href="#">비밀번호 찾기</a></div>
          <input type="hidden" name="_wp_http_referer" value="/cf-campaign-form/">           
        </form>
        <div class="haveaccount"><span>아직 회원가입을 안하셨나요?</span></div>
        <p>
          <a data-toggle="modal" data-target="#register" href="#" data-dismiss="modal">회원 가입</a>
        </p>
      </div>
    </div>
  </div>
</div>

<!-- modal#2 회원가입 -->
<div class="modal fade" id="register" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="myModalLabel">회원 가입</h4>
      </div>
      <div class="modal-body">
        <form id="register" action="#" method="post">
          <div class="login-error alert alert-danger" role="alert" style="display: none;"></div>
          <input type="email" id="email" name="email" class="form-control" autocomplete="username" placeholder="이메일">
          <input type="password" id="password" name="password" class="form-control" autocomplete="new-password" placeholder="비밀번호">
          <input type="password" id="passwordconfirm" name="passwordconfirm" class="form-control" autocomplete="new-password" placeholder="비밀번호 확인">
          <div class="form-group form-check justify-content-start">
            <div class="register-agreement">
              <input type="checkbox" class="form-check-input" id="servicetermCheck" name="serviceterm"> 
              <label class="form-check-label" for="servicetermCheck">
                <a data-toggle="modal" data-target="#serviceterm" data-dismiss="modal">서비스 이용약관 동의</a>
              </label>
            </div>
            <div class="register-agreement">
              <input type="checkbox" class="form-check-input" id="privacyCheck" name="privacy"> 
              <label class="form-check-label" for="privacyCheck">
                <a data-toggle="modal" data-target="#privacyagree" data-dismiss="modal">개인정보 수집 및 이용동의</a>
              </label>
            </div>
          </div>
          <button type="submit" class="btn btn-primary register_button">회원 가입</button>
          <input type="hidden" id="security" name="security" value="c28781e68d"><input type="hidden" name="_wp_http_referer" value="/cf-campaign-form/">
        </form>
        <p class="condition">회원가입약관, 서비스이용약관에 동의합니다. </p>
        <div class="haveaccount"><span>이미 회원이신가요?</span></div>
        <p>
          <a data-toggle="modal" data-target="#myModal" href="#" data-dismiss="modal">login</a>
        </p>
      </div>
    </div>
  </div>
</div>

<!-- modal#3 서비스 이용약관 -->
<div class="modal fade" id="serviceterm" tabindex="-1" role="dialog" aria-labelledby="servicetermLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-toggle="modal" data-target="#register" href="#" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="servicetermLabel">서비스 이용약관</h4>
      </div>
      <div class="modal-body text-align-left">
        가장 우리 자신과 이 말이다. 같은 그들의 기관과 인생을 것이다. 우는 낙원을 붙잡아 인간은 못할 위하여, 구하지 것이다. 온갖 꽃이 있는 못할 황금시대다. 주는 끓는 그들의 가슴이 바로 그러므로 것이다. 간에 인생에 노래하며 것이다. 피부가 이 인도하겠다는 철환하였는가? 내는 사랑의 옷을 피에 위하여, 가슴이 인도하겠다는 사막이다. 구하지 그들의 뜨고, 철환하였는가? 역사를 길을 고동을 끓는다.

소리다.이것은 불어 생명을 풀밭에 인간에 평화스러운 작고 칼이다. 사람은 유소년에게서 착목한는 피어나기 것이다.보라, 있는 봄바람이다. 때에, 능히 전인 속잎나고, 아니다. 이상 예가 이상은 위하여, 보배를 불어 위하여서. 때까지 우는 작고 있는 가치를 운다. 그들의 장식하는 하였으며, 뭇 얼마나 심장의 것이다. 웅대한 같이 싶이 실로 귀는 발휘하기 사랑의 얼마나 가는 것이다. 귀는 뭇 얼음 때에, 동력은 얼음이 피가 것이다. 발휘하기 이것은 기쁘며, 커다란 설레는 천지는 구할 싹이 불러 때문이다.

하는 원질이 봄날의 착목한는 인간에 운다. 스며들어 설레는 가슴에 어디 것이다. 인생의 석가는 물방아 것은 앞이 안고, 몸이 거친 것이다. 그러므로 거친 품으며, 방황하여도, 것이다. 가는 심장은 되는 생명을 장식하는 황금시대를 보내는 광야에서 같이, 칼이다. 발휘하기 있는 길을 위하여 가는 끓는 봄바람이다. 인류의 작고 얼마나 방황하여도, 끓는다. 피가 힘차게 때에, 같이 곳이 사막이다. 아름답고 가장 보는 곧 것이다.
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#register" href="#" data-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>    
    
<!-- modal#4 개인정보수집이용 동의 -->
<div class="modal fade" id="privacyagree" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-toggle="modal" data-target="#register" href="#" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="myModalLabel">개인정보 수집 및 이용동의</h4>
      </div>
      <div class="modal-body text-align-left  ">
패, 못 이름을 이름자 멀리 새워 별 버리었습니다. 속의 까닭이요, 패, 별이 버리었습니다. 밤이 묻힌 걱정도 같이 벌써 이제 너무나 까닭입니다. 별이 내일 계집애들의 나의 별 어머님, 강아지, 계십니다. 헤일 까닭이요, 패, 있습니다. 까닭이요, 라이너 경, 지나가는 가슴속에 멀리 못 헤일 까닭입니다. 새겨지는 별을 하나에 이름을 벌써 별 별 듯합니다. 책상을 덮어 별들을 하나에 있습니다. 사람들의 하나의 없이 책상을 나의 위에 무덤 한 거외다.

나의 너무나 어머니, 그러나 된 내일 봅니다. 가슴속에 봄이 잔디가 나의 별빛이 하나에 불러 오면 밤이 계십니다. 청춘이 위에도 잠, 이런 멀듯이, 내일 있습니다. 별을 내 우는 멀리 까닭입니다. 까닭이요, 써 별에도 계십니다. 사랑과 가슴속에 릴케 말 다하지 언덕 거외다. 차 없이 때 노루, 가을 마디씩 별이 까닭입니다. 다하지 언덕 다 불러 아직 하나에 가슴속에 까닭이요, 듯합니다. 덮어 토끼, 사랑과 없이 노새, 불러 거외다. 다 아침이 부끄러운 아이들의 듯합니다. 지나고 하나에 하나의 새겨지는 우는 된 가득 사람들의 까닭입니다.

둘 시와 무덤 된 계십니다. 둘 이 하나 지나가는 버리었습니다. 노루, 이름과, 남은 무성할 동경과 까닭입니다. 이름과, 아무 벌레는 쉬이 까닭이요, 하나의 거외다. 다하지 같이 이름과 어머니, 이국 헤일 내린 잔디가 듯합니다. 잔디가 사랑과 때 파란 언덕 이름과, 계십니다. 까닭이요, 시인의 나는 아이들의 내일 나는 묻힌 계십니다. 그리워 이웃 토끼, 하나의 걱정도 까닭입니다. 쓸쓸함과 풀이 아침이 어머님, 걱정도 불러 사람들의 이름과 별 버리었습니다.
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-toggle="modal" data-target="#register" href="#" data-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>

2. Dynamically load content in Bootstrap Modal with AJAX

Bootstrap Modal의 Contents를 Dynamic하게 Load하는 방법에 대한 강좌가 있어 참고한다.

php (html)에서 button을 누르면 data 속성들을 함께 전달하고, js는 그 내용에 따라 handler php를 호출하고, 그 결과 내용을 modal-body에 write 해주는 방식이다.

다음과 같은 순서로 적용해본다.


1) HTML (Login Modal)

기존에 Login, Register, Service Term, Privacy 4개로 이루어져 있던 Modal 사용 구조는 Login, Register, Agreement로 변경한다.

이유는 첫째, Login과 Register Modal 부분은 코드양이 크게 길지 않아 굳이 js를 통해 동적으로 불러올 필요가 없을 것으로 판단하였다.

둘째, Service Term과 Privacy Modal 부분은 약관과 개인정보수집 동의 내용이 길어 동적으로 불러오되, Register Modal에 동적으로 덮어 씌우는 대신 별도의 Agreement Modal을 두고 활용하는 것으로 변경하였다.

<div class="login-button">
  <a class="my-login" data-toggle="modal" data-target="#myModal" href="#">Login</a>   
</div>

<!-- modal#1 로그인 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="myModalLabel">로그인</h4>
      </div>
      <div class="modal-body">
        <form id="login" action="" method="post"> <!-- 필요한 action 지정 -->
          <div class="login-error alert alert-danger" role="alert" style="display: none;"></div>
          <input type="email" id="login_email" name="email" class="form-control" autocomplete="username" placeholder="e-mail을 적어주세요"> 
          <input type="password" id="login_password" name="password" class="form-control" autocomplete="current-password" placeholder="비밀번호">
          <input type="checkbox" id="remember" name="remember"><label for="cbox2">기억하기</label>
          <button type="submit" class="btn btn-primary submit_button">로그인</button>
          <div class="lost-pass"><a href="#">비밀번호 찾기</a></div>
          <input type="hidden" name="_wp_http_referer" value="/cf-campaign-form/">           
        </form>
        <div class="haveaccount"><span>아직 회원가입을 안하셨나요?</span></div>
        <p>
          <a data-toggle="modal" data-target="#register" href="#" data-dismiss="modal">회원 가입</a>
        </p>
      </div>
    </div>
  </div>
</div>

<!-- modal#2 회원가입 -->
<div class="modal fade" id="register" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="myModalLabel">회원 가입</h4>
      </div>
      <div class="modal-body">
        <form id="register" action="#" method="post">
          <div class="login-error alert alert-danger" role="alert" style="display: none;"></div>
          <input type="email" id="email" name="email" class="form-control" autocomplete="username" placeholder="이메일">
          <input type="password" id="password" name="password" class="form-control" autocomplete="new-password" placeholder="비밀번호">
          <input type="password" id="passwordconfirm" name="passwordconfirm" class="form-control" autocomplete="new-password" placeholder="비밀번호 확인">
          <div class="form-group form-check justify-content-start">
            <div class="register-agreement">
              <input type="checkbox" class="form-check-input" id="servicetermCheck" name="serviceterm"> 
              <label class="form-check-label" for="servicetermCheck">
                <a data-toggle="modal" data-target="#agreement" data-type="#serviceterm" class="show-agreement">서비스 이용약관 동의</a>
              </label>
            </div>
            <div class="register-agreement">
              <input type="checkbox" class="form-check-input" id="privacyCheck" name="privacy"> 
              <label class="form-check-label" for="privacyCheck">
                <a data-toggle="modal" data-target="#agreement" data-type="#privacyagree" class="show-agreement">개인정보 수집 및 이용동의</a>
              </label>
            </div>
          </div>
          <button type="submit" class="btn btn-primary register_button">회원 가입</button>
          <input type="hidden" id="security" name="security" value="c28781e68d"><input type="hidden" name="_wp_http_referer" value="/cf-campaign-form/">
        </form>
        <p class="condition">회원가입약관, 서비스이용약관에 동의합니다. </p>
        <div class="haveaccount"><span>이미 회원이신가요?</span></div>
        <p>
          <a data-toggle="modal" data-target="#myModal" href="#" data-dismiss="modal">login</a>
        </p>
      </div>
    </div>
  </div>
</div>

<!-- modal#3 서비스 이용약관, 개인정보수집동의 -->
<div class="modal fade" id="agreement" tabindex="-1" role="dialog" aria-labelledby="agreementLabel" aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-dialog-centered" role="document">
    <div class="modal-content">
      <div class="modal-header">
        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
        <h4 class="modal-title" id="agreementLabel"></h4>
      </div>
      <div class="modal-body text-align-left" id="agreementBody">
      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
      </div>
    </div>
  </div>
</div>    

2) .js 스크립트

Service Term과 Privacy는 별도의 포스팅 또는 페이지로 게시하여 회원가입 시 외에도 사용자가 요청할 경우 보여줄 수 있게 한다.

Service Term은 https://bekseju9n.pe.kr/dummy-text-1/ (page id 3316)이라 하고, Privacy는 https://bekseju9n.pe.kr/dummy-text-2/ (3318)라 하자.

강좌에서 동적으로 DB Query를 날려서 데이터를 받아오는 복잡함에 비해, 단순히 modal-body에 위 2개 페이지의 contents를 읽어와서 덮어써주면 끝난다.

jQuery(document).ready(function($){
    $('.show-agreement').click(function(){
//    	console.log('약관동의 등 scirpt 시작');
    	var agreementType = $(this).data('type');
    	
    	// AJAX request
        jQuery.ajax({
    	    url: show_agreement.ajax_url,
    	    type: 'post',
    	    data: {
    	    	action: 'get_agreement',
    	    	agreementType: agreementType},
    	    success: function(response){ 
    	      // Add response in Modal body
    	    	$('#agreementLabel').html(response.title);
    	    	$('#agreementBody').html(response.content);
    	    }
    	  });
    });
});

3) PHP Handler

위에 .js 에서 호출하는 get_agreement 액션을 정의한다. wordpress에서 handler는 wp_ajax_nopriv_***, wp_ajax_*** 형태로 add action 하면 된다. https://bekseju9n.pe.kr/ajax-in-wordpress/ 참고.

theme이나 plugin의 functions.php 에 다음을 추가한다.

add_action( 'wp_ajax_nopriv_get_agreement', 'get_agreement' ); // For non logged in users
add_action( 'wp_ajax_get_agreement', 'get_agreement' );  // For logged in users.
function get_agreement() {
	
	$agreementType = sanitize_text_field($_POST['agreementType']);
	$postid = '';
	
	if ($agreementType == "#serviceterm") {
		$postid = '3316';
	} elseif ($agreementType == "#privacyagree") {
		$postid = '3318';
	}
	
	$title = get_the_title($postid);
	$content = get_post_field('post_content', $postid);
	wp_send_json(array(
			'title' => $title,
			'content' => $content
	));
	wp_die();
}

3. 적용 결과

적용된 내용을 확인하기 위해 이 positing에 bootstrap javascript와 css를 추가하였다. 1


Footnotes

  1. https://www.wpbeginner.com/wp-tutorials/how-to-easily-add-javascript-in-wordpress-pages-or-posts/

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다