본문 바로가기
재밌는 IT 개발/그누보드 테마 제작기(記)

그누보드 테마 제작 30 - FAQ 페이지 개발

by 만수킴 2020. 7. 22.

이번엔 FAQ 페이지 개발에 들어갑니다.

그누보드 기본 테마는 어떻게 생겼는지 보겠습니다.

그누보드 기본테마의 FAQ 화면

음... 이게 뭐죠... 아무것도 없네요...
하단에 톱니바튀가 보이시나요?
그 곳이 FAQ의 화면 내용을 셋팅하는 곳입니다.
들어가서 보겠습니다.

FAQ 관리를 위한 어드민 페이지와 셋팅 내용

먼저 그누보드의 FAQ는 어떤 방식으로 작동되는 것인지 확인이 필요하겠네요.
그래서 위와 같이 셋팅을 한 후 어떻게 바뀌는지 보겠습니다.

어드민의 셋팅내용이 적용된 FAQ 화면 모습

다음은, FAQ관리 메뉴를 확인하겠습니다.

어드민의 FAQ 관리 메뉴 모습

"자주하시는 질문"은 하나의 카테고리였군요.
같은 방식으로 카테고리를 계속 늘려나갈 수 있겠습니다.

FAQ의 카테고리를 확장한 모습

이제 어드민 설정의 내용이 적용된 화면을 보시겠습니다.

어드민의 셋팅 내용이 적용된 화면

테스트 글도 몇개 작성해보겠습니다.
FAQ니까 당연히 어드민에서 작성 및 관리됩니다.

FAQ의 글을 관리하기 위한 어드민 메뉴 구성과 순서

저도 몇개 입력해본 후의 결과 화면을 보겠습니다.

샘플데이터를 입력한 후의 FAQ 화면


이제 개발만 하면 되겠네요.
먼저 개발해야 하는 테마 화면은 어떤 모습인지 확인해보겠습니다.

제작중인 테마에서의 FAQ 페이진 모습

나쁘지 않아보이지만, CSS를 주석 처리하면... 

제작중인 테마 - CSS를 주석처리 한 후의 FAQ 페이진 모습


화면 구상을 해야 하는 단계네요.
항상 시간을 제일 많이 아니 거의 소비하는 단계입니다.
상단 검색폼이나, 카테고리 출력하는 부분은
이미 다 해 봤던 부분이니 큰 어려움은 없을 것 같구요.
중간에 Q와 A를 보여주는 부분만 정하면 되겠네요.

preview.keenthemes.com/metronic/demo1/custom/apps/support-center/home-1.html

 

Metronic | Home 1

Windows 10 automatically downloads and installs updates to make sure your device is secure and up to date. This means you receive the latest fixes and security updates, helping your device run efficiently and stay protected. In most cases, restarting your

preview.keenthemes.com

preview.keenthemes.com/metronic/demo1/custom/apps/support-center/home-2.html

 

Metronic | Home 2

Windows 10 automatically downloads and installs updates to make sure your device is secure and up to date. This means you receive the latest fixes and security updates, helping your device run efficiently and stay protected. In most cases, restarting your

preview.keenthemes.com

preview.keenthemes.com/metronic/demo1/custom/apps/support-center/faq-1.html

 

Metronic | FAQ

My Profile Account settings and more update

preview.keenthemes.com

위 화면들 중 하나를 참조하면 될 듯 합니다.
음... 3번째 faq-1.html의 일부를 가져오기로 합니다.

Metronic Admin Template의 faq 리스트 샘플


정해졌으니 바로 대략적인 화면 구성 단계를 진행합니다.
새글 페이지의 기본 구성을 가져와서 붙이고,
그 중간에 Metronic Admin에서 고른 템플릿 코드를 넣어보겠습니다.
(사실 페이지 통째로 저 화면을 넣고 싶었으나... 시간이 또 오래 걸릴 듯 하여 패스..)
대충 이런 모습...

새글과 템플릿 코드를 이용하여 만든 FAQ 화면

이제 원 테마의 코드를
제작 중 테마로 옮기는 작업을 진행합니다.

검색 영역 작업하고, 카테고리 영역 후
리스트 작업과 페이징 작업만 하면 끝납니다.

FAQ화면의 검색 영역 완료된 모습

 

이런... 카테고리 영역을 고려 안했었네요.
FAQ 글 올라가는 영역도 bootstrap의 card를 이용하고 있는데요.
마침 header영역이 없으니 그걸 이용하겠습니다.
우선 $faq_master_list 에는 어떤 내용이 들어 있는지 확인합니다.

=====================

FAQ 마스터 => Array
(
    [1] => Array
        (
            [fm_id] => 1
            [fm_subject] => 자주하시는 질문
            [fm_head_html] => <p></p>
<table bgcolor="#33ff33" cellpadding="1" cellspacing="0" style="border-color:#ff0000;border-style:solid;border-width:1px;border-collapse:collapse;width:100%;">
   <tbody>
      <tr>
         <td style="text-align:center;border-style:solid;border-width:1px;border-color:#ff0000;">&nbsp;FAQ 상단 내용 샘플</td>
      </tr>
   </tbody>
</table>

            [fm_tail_html] => <p></p>
<table bgcolor="#99ff00" cellpadding="1" cellspacing="0" style="border-color:#ff0000;border-style:solid;border-width:1px;border-collapse:collapse;width:100%;">
   <tbody>
      <tr>
         <td style="border-style:solid;border-width:1px;border-color:#ff0000;">&nbsp;FAQ 하단 내용 샘플</td>
      </tr>
   </tbody>
</table>

            [fm_mobile_head_html] => 
            [fm_mobile_tail_html] => 
            [fm_order] => 0
        )

    [2] => Array
        (
            [fm_id] => 2
            [fm_subject] => 회원 관련
            [fm_head_html] => <p>
   <table bgcolor="#99ccff" cellpadding="1" cellspacing="0" style="border-color: #ff0000; border-style: solid; border-width: 1px; border-collapse: collapse; width: 100%;">
      <tbody>
         <tr>
            <td style="text-align: center; border-style: solid; border-width: 1px; border-color: #ff0000;">&nbsp;FAQ - 회원관련 상단 내용 샘플</td>
         </tr>
      </tbody>
   </table>
</p>

            [fm_tail_html] => <p>
   <table bgcolor="#99ccff" cellpadding="1" cellspacing="0" style="border-color: #ff0000; border-style: solid; border-width: 1px; border-collapse: collapse; width: 100%;">
      <tbody>
         <tr>
            <td style="text-align: center; border-style: solid; border-width: 1px; border-color: #ff0000;">&nbsp;FAQ - 회원관련 하단 내용 샘플</td>
         </tr>
      </tbody>
   </table>
</p>

            [fm_mobile_head_html] => 
            [fm_mobile_tail_html] => 
            [fm_order] => 1
        )

    [3] => Array
        (
            [fm_id] => 3
            [fm_subject] => 포인트 관련
            [fm_head_html] => <p>
   <table bgcolor="#99ccff" cellpadding="1" cellspacing="0" style="border-color: #ff0000; border-style: solid; border-width: 1px; border-collapse: collapse; width: 100%;">
      <tbody>
         <tr>
            <td style="text-align: center; border-style: solid; border-width: 1px; border-color: #ff0000;">&nbsp;FAQ - 포인트 관련 상단 내용 샘플</td>
         </tr>
      </tbody>
   </table>
</p>

            [fm_tail_html] => <p>
   <table bgcolor="#99ccff" cellpadding="1" cellspacing="0" style="border-color: #ff0000; border-style: solid; border-width: 1px; border-collapse: collapse; width: 100%;">
      <tbody>
         <tr>
            <td style="text-align: center; border-style: solid; border-width: 1px; border-color: #ff0000;">&nbsp;FAQ - 포인트 관련 하단 내용 샘플</td>
         </tr>
      </tbody>
   </table>
</p>

            [fm_mobile_head_html] => 
            [fm_mobile_tail_html] => 
            [fm_order] => 2
        )

)
===============================

FAQ 마스터를 등록한 내용이 그대로 들어 있습니다.
카테고리 영역을 만들기 위해서는
fm_id와 fm_subject 필드만 사용하겠네요.

FAQ 페이지의 FAQ 마스터 영역이 완료된 모습

 

이제 리스트 작업입니다.
페이징이야 뭐 함수만 바꾸면 되니 일도 아니고,
요것만 하면 끝나겠네요.
$faq_list의 내용부터 로그를 찍어 확인해봅니다.

=====================

FAQ 리스트 => Array
(
    [0] => Array
        (
            [fa_id] => 1
            [fm_id] => 2
            [fa_subject] => 회원 관련 <b class="sch_word">질문</b> 첫번째입니다.
<p>그래요. 그렇습니다.</p>
<p>
   <img src="http://hunnov5.tank.com/data/editor/2007/20200711124322_b04d4d77aa85b84d85067c9ea80318bc_emwp.jpg" alt="0bd1b4c37434719710d2cfa7b8cabde2.jpg" style="width:500px;height:700px;" /></p>

            [fa_content] => <p>회원 관련 <b class="sch_word">질문</b> 첫번째에 대한 답변입니다.</p>
<p>그래요. 그렇습니다.</p>
<p>
   <img src="http://hunnov5.tank.com/data/editor/2007/20200711124352_b04d4d77aa85b84d85067c9ea80318bc_b0ox.jpg" alt="54ad7585d06399f1abdead8207143acc.jpg" style="width:470px;height:960px;" /></p>

            [fa_order] => 1
        )

    [1] => Array
        (
            [fa_id] => 2
            [fm_id] => 2
            [fa_subject] => <p>FAQ 회원 관련 두 번째 <b class="sch_word">질문</b> 입력입니다.</p>

            [fa_content] => <p>FAQ 회원 관련 두 번째 <b class="sch_word">질문</b>에 대한 답변 입력입니다.</p>

            [fa_order] => 2
        )

)
===============================

fa_id, fa_subject, fa_content 값을 이용하게 되겠습니다.
아이고... 사소한 줄맞추기 때문에 엄청 고생했지만,
포기하면 쉬운 법.
포기하고 완료하였습니다.

완성된 FAQ(자주하는 질문)의 화면

그리고 완료된 소스입니다.

<?php
if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가

// add_stylesheet('css 구문', 출력순서); 숫자가 작을 수록 먼저 출력됨
//add_stylesheet('<link rel="stylesheet" href="'.$faq_skin_url.'/style.css">', 0);
?>

<?php include G5_THEME_PARTIALS_PATH ."/_subheader/subheader-v1.php"; ?>

<!-- FAQ 시작 { -->
<div class="d-flex flex-column-fluid">
    <!--begin::Container-->
    <div class="container">



<?php
if ($himg_src)
    echo '<div id="faq_himg" class="faq_img"><img src="'.$himg_src.'" alt=""></div>';

// 상단 HTML
echo '<div id="faq_hhtml">'.conv_content($fm['fm_head_html'], 1).'</div>';
?>

<!--begin::검색영역-->
<div class="card card-custom">
    <!--begin::Body-->
    <div class="card-body bg-dark-o-30 rounded pt-10 pb-8">
        <form name="faq_search_form" method="get">
        <input type="hidden" name="fm_id" value="<?php echo $fm_id;?>">

            <div class="form-row">
                <span class="sch_tit sound_only">FAQ 검색</span>
                <div class="col-4 offset-3">
                    <label for="stx" class="sound_only">검색어<strong class="sound_only"> 필수</strong></label>
                    <input type="text" name="stx" value="<?php echo $stx ?>" id="mb_id" required class="form-control form-control-lg rounded frm_input" >
                </div>
                <div class="col-4 mt-1">
                    <button type="submit" class="btn btn-dark btn_submit"><i class="fa fa-search" aria-hidden="true"></i> 검색</button>
                </div>
            </div>
        </form>
    </div>
    <!--end::Body-->
</div>
<!--end::검색 영역-->


<div class="card card-custom gutter-b mt-5">
<?php                                                           //tLog("FAQ 마스터", $faq_master_list);
if( count($faq_master_list) ){
?>
    <!--begin::FAQ 마스터 영역-->
    <div class="card-header row row-marginless align-items-center flex-wrap py-3 pb-0 h-auto">
        <h2 class="sound_only">자주하시는질문 분류</h2>
        <div class="col-12 col-sm-12 align-items-start bo_cate">
            <?php
            foreach( $faq_master_list as $v ){
                $category_msg = '';
                $category_option = '';
                $is_open = false;
                if($v['fm_id'] == $fm_id) $is_open = true; // 현재 선택된 카테고리라면 true
            ?>
            <button type="button" onclick="location.href='<?php echo $category_href;?>?fm_id=<?php echo $v['fm_id'];?>';" class="btn <?php echo $is_open ? "btn-primary" : "btn-outline-secondary"; ?> mr-3">
                <span class="font-weight-bold mr-2"><?php echo $category_msg.$v['fm_subject'];?></span>
                <?php echo $is_open ? '<span class="sound_only">열린 분류 </span>' : ''; ?>
            </button>
            <?php
            }
            ?>
        </div>
    </div>
    <!--end::FAQ 마스터 영역-->
<?php } ?>

    <!--begin::FAQ 리스트 영역-->
    <h2 class="sound_only"><?php echo $g5['title']; ?> 목록</h2>
    <div class="card-body table-responsive px-5 pt-1">
        <!-- begin::faq lists -->
        <div class="row col-12">
            <!--begin::Tab Content-->
            <div class="tab-content w-100">
                <!--begin::Accordion-->
                <div class="accordion accordion-light accordion-light-borderless accordion-svg-toggle" id="faq">
<?php                                                           //tLog("FAQ 리스트", $faq_list);
if( count($faq_list) ){ // FAQ 내용
    foreach($faq_list as $key=>$v){
        if(empty($v)) continue;
?>
                    <!--begin::card for faq-->
                    <div class="card border-bottom border-red">
                        <div class="card-header" id="faqHeading<?php echo $v['fa_id']; ?>">
                            <a class="card-title text-dark collapsed" data-toggle="collapse" href="#faq<?php echo $v['fa_id']; ?>" aria-expanded="false" aria-controls="faq<?php echo $v['fa_id']; ?>" role="button">
                                <span class="svg-icon svg-icon-primary">
                                    <!--begin::Svg Icon | path:/metronic/theme/html/demo1/dist/assets/media/svg/icons/Navigation/Angle-double-right.svg-->
                                    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="0 0 24 24" version="1.1">
                                        <g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
                                            <polygon points="0 0 24 0 24 24 0 24"></polygon>
                                            <path d="M12.2928955,6.70710318 C11.9023712,6.31657888 11.9023712,5.68341391 12.2928955,5.29288961 C12.6834198,4.90236532 13.3165848,4.90236532 13.7071091,5.29288961 L19.7071091,11.2928896 C20.085688,11.6714686 20.0989336,12.281055 19.7371564,12.675721 L14.2371564,18.675721 C13.863964,19.08284 13.2313966,19.1103429 12.8242777,18.7371505 C12.4171587,18.3639581 12.3896557,17.7313908 12.7628481,17.3242718 L17.6158645,12.0300721 L12.2928955,6.70710318 Z" fill="#000000" fill-rule="nonzero"></path>
                                            <path d="M3.70710678,15.7071068 C3.31658249,16.0976311 2.68341751,16.0976311 2.29289322,15.7071068 C1.90236893,15.3165825 1.90236893,14.6834175 2.29289322,14.2928932 L8.29289322,8.29289322 C8.67147216,7.91431428 9.28105859,7.90106866 9.67572463,8.26284586 L15.6757246,13.7628459 C16.0828436,14.1360383 16.1103465,14.7686056 15.7371541,15.1757246 C15.3639617,15.5828436 14.7313944,15.6103465 14.3242754,15.2371541 L9.03007575,10.3841378 L3.70710678,15.7071068 Z" fill="#000000" fill-rule="nonzero" opacity="0.3" transform="translate(9.000003, 11.999999) rotate(-270.000000) translate(-9.000003, -11.999999)"></path>
                                        </g>
                                    </svg>
                                    <!--end::Svg Icon-->
                                </span>
                                <div class="card-label text-dark pl-4 pt-5"><?php echo conv_content($v['fa_subject'], 1); ?></div>
                            </a>
                        </div>
                        <div id="faq<?php echo $v['fa_id']; ?>" class="collapse" aria-labelledby="faqHeading<?php echo $v['fa_id']; ?>" data-parent="#faq" style="">
                            <div class="card-body text-dark-50 font-size-lg pl-12">
                                <?php echo conv_content($v['fa_content'], 1); ?>
                            </div>
                        </div>
                    </div>
                    <!--end::card for faq-->
<?php
    }
} else {
    if( $stx ){
        echo '<!--begin::card for faq--><div class="card"><div class="card-header"><div class="card-label text-dark text-center h-150px pt-12">검색된 게시물이 없습니다.</div></div></div><!--end::card for faq-->';
    } else {
        echo '<!--begin::card for faq--><div class="card"><div class="card-header"><div class="card-label text-dark text-center h-150px pt-12">등록된 FAQ가 없습니다.';
        if($is_admin)
            echo '<br><a href="'.G5_ADMIN_URL.'/faqmasterlist.php">FAQ를 새로 등록하시려면 FAQ관리</a> 메뉴를 이용하십시오.';
        echo '</div></div></div><!--end::card for faq-->';
    }
}
?>
                </div>
                <!--begin::Accordion-->
            </div>
            <!--begin::Tab Content-->
        </div>
        <!-- begin::faq lists -->

<?php if ($admin_href) { ?>
        <div class="col-12 d-flex align-items-center justify-content-sm-end text-right mt-2">
            <span onclick="location.href='<?php echo G5_ADMIN_URL.'/faqmasterlist.php'; ?>';" class="btn btn-default btn-icon btn-sm btn-danger mr-2" data-toggle="tooltip" title="" data-original-title="관리자">
                <i class="fa fa-cog fa-spin fa-fw"></i><span class="sound_only">관리자</span>
            </span>
        </div>
<?php } ?>

    <!--end::faq 리스트 영역-->
    </div><!--end::card-Body-->
    <!--begin::Card footer 영역-->
    <?php if ( $total_page > 1 ) { ?>
    <div class="card-footer">
        <?php echo get_paging_mt703($page_rows, $page, $total_page, $_SERVER['SCRIPT_NAME'].'?'.$qstr.'&amp;page=');  //tLog("page_html", "[". $page_html ."]"); ?>
    </div>
    <?php } ?>
    <!--end::Card footer 영역-->
</div><!--end::card-Header-->

<?php
// 하단 HTML
echo '<div id="faq_thtml">'.conv_content($fm['fm_tail_html'], 1).'</div>';

if ($timg_src)
    echo '<div id="faq_timg" class="faq_img"><img src="'.$timg_src.'" alt=""></div>';
?>



    </div>
</div>
<!-- } FAQ 끝 -->


<script src="<?php echo G5_JS_URL; ?>/viewimageresize.js"></script>
<script>
jQuery(function() {
    $(".closer_btn").on("click", function() {
        $(this).closest(".con_inner").slideToggle('slow', function() {
			var $h3 = $(this).closest("li").find("h3");

			$("#faq_con li h3").removeClass("faq_li_open");
			if($(this).is(":visible")) {
				$h3.addClass("faq_li_open");
			}
		});
    });
});

function faq_open(el)
{
    var $con = $(el).closest("li").find(".con_inner"),
		$h3 = $(el).closest("li").find("h3");

    if($con.is(":visible")) {
        $con.slideUp();
		$h3.removeClass("faq_li_open");
    } else {
        $("#faq_con .con_inner:visible").css("display", "none");

        $con.slideDown(
            function() {
                // 이미지 리사이즈
                $con.viewimageresize2();
				$("#faq_con li h3").removeClass("faq_li_open");

				$h3.addClass("faq_li_open");
            }
        );
    }

    return false;
}
</script>

 

이제 접속자 리스트와 투표(POLL), 그리고 일반페이지들이 남았습니다.
그누보드 정말 많은 기능들이 숨어 있군요.

다음 포스팅때 또 뵐게요~~

 

댓글