사용자 도구

사이트 도구


사이드바

기술문서:오픈소스:dokuwiki

문서의 이전 판입니다!


DokuWiki

본 문서는 2020-07-29a "Hogfather" 1) 버전을 기준으로 작성되었습니다.
- 사용법
- 플러그인
- 커스터마이징
- 관리

사용법

플러그인

커스터마이징

페이지 삭제

  • data/pages/playground
  • data/pages/wiki

기본 템플릿

이미지 교체

  • lib/tpl/dokuwiki/images/favicon.ico
  • lib/tpl/dokuwiki/images/apple-touch-icon.png
  • lib/tpl/dokuwiki/images/logo.png

logo 대체 텍스트

        <h1><?php
            // get logo either out of the template images folder or data/media folder
            $logoSize = array();
            $logo = tpl_getMediaFile(array(':wiki:logo.png', ':logo.png', 'images/logo.png'), false, $logoSize);

            // display logo and wiki title in a link to the home page
            tpl_link(
                wl(),
                '<img src="'.$logo.'" '.$logoSize[3].' alt="'.$conf['title'].'" /> <span>'.$conf['title'].'</span>',
                'accesskey="h" title="[H]"'
            );
        ?></h1>

<!--<div id="dokuwiki__footer"><div class="pad">
    <?php tpl_license(''); // license text ?>

    <div class="buttons">
        <?php
            tpl_license('button', true, false, false); // license button, no wrapper
            $target = ($conf['target']['extern']) ? 'target="'.$conf['target']['extern'].'"' : '';
        ?>
        <a href="https://www.dokuwiki.org/donate" title="Donate" <?php echo $target?>><img
            src="<?php echo tpl_basedir(); ?>images/button-donate.gif" width="80" height="15" alt="Donate" /></a>
        <a href="https://php.net" title="Powered by PHP" <?php echo $target?>><img
            src="<?php echo tpl_basedir(); ?>images/button-php.gif" width="80" height="15" alt="Powered by PHP" /></a>
        <a href="//validator.w3.org/check/referer" title="Valid HTML5" <?php echo $target?>><img
            src="<?php echo tpl_basedir(); ?>images/button-html5.png" width="80" height="15" alt="Valid HTML5" /></a>
        <a href="//jigsaw.w3.org/css-validator/check/referer?profile=css3" title="Valid CSS" <?php echo $target?>><img
            src="<?php echo tpl_basedir(); ?>images/button-css.png" width="80" height="15" alt="Valid CSS" /></a>
        <a href="https://dokuwiki.org/" title="Driven by DokuWiki" <?php echo $target?>><img
            src="<?php echo tpl_basedir(); ?>images/button-dw.png" width="80" height="15"
            alt="Driven by DokuWiki" /></a>
    </div>
</div></div>--><!-- /footer -->

문서 정보 제거

            <div id="dokuwiki__content"><div class="pad group">
                <?php html_msgarea() ?>

                <div class="pageId"><span><?php echo hsc($ID) ?></span></div>

                <div class="page group">
                    <?php tpl_flush() ?>
                    <?php tpl_includeFile('pageheader.html') ?>
                    <!-- wikipage start -->
                    <?php tpl_content() ?>
                    <!-- wikipage stop -->
                    <?php tpl_includeFile('pagefooter.html') ?>
                </div>

                <div class="docInfo"><?php /*tpl_pageinfo()*/ ?></div>

                <?php tpl_flush() ?>
            </div></div><!-- /content -->

하단 여백 제거

.dokuwiki .wrapper {
    /*margin-bottom: 1.4em;*/
}

테이블 오버 효과 제거

.dokuwiki table.inline tr:hover td {
    /*background-color: @ini_background_alt;*/
}

.dokuwiki table.inline tr:hover th {
    /*background-color: @ini_border;*/
}

테이블 줄 바꿈 제거

.dokuwiki div.table[class*="sectionedit"] {
	white-space: nowrap !important;
}

테이블 정중앙 정렬

.dokuwiki div.table[class*="sectionedit"] table :is(th, td).centeralign {
	vertical-align: middle !important;
}

문서 편집 설명 제거


문서 편집 에디터 수정

    initSizeCtl: function(ctlarea,editor){
        var $ctl      = jQuery(ctlarea),
            $textarea = jQuery(editor);

        if($ctl.length === 0 || $textarea.length === 0) {
            return;
        }

        $textarea.css('height', DokuCookie.getValue('sizeCtl') || '400px');

        var wrp = DokuCookie.getValue('wrapCtl');
        if(wrp){
            dw_editor.setWrap($textarea[0], wrp);
        } // else use default value

        jQuery.each([
            ['larger', function(){dw_editor.sizeCtl(editor,100);}],
            ['smaller', function(){dw_editor.sizeCtl(editor,-100);}],
            ['wrap', function(){dw_editor.toggleWrap(editor);}]
        ], function (_, img) {
            jQuery(document.createElement('img'))
                .attr('src', DOKU_BASE+'lib/images/' + img[0] + '.gif')
                .attr('alt', '')
                .on('click', img[1])
                .appendTo($ctl);
        });
    },

자동 약어 힌트 비활성화

#ACL          Access Control List
#AFAICS       As far as I can see
#AFAIK        As far as I know
#AFAIR        As far as I remember
#API          Application Programming Interface
#ASAP         As soon as possible
#ASCII        American Standard Code for Information Interchange
#BTW          By the way
#CMS          Content Management System
#CSS          Cascading Style Sheets
#DNS          Domain Name System
#EOF          End of file
#EOL          End of line
#EOM          End of message
#EOT          End of text
#FAQ          Frequently Asked Questions
#FTP          File Transfer Protocol
#FOSS         Free & Open-Source Software
#FLOSS        Free/Libre and Open Source Software
#FUD          Fear, Uncertainty, and Doubt
#FYI          For your information
#GB           Gigabyte
#GHz          Gigahertz
#GPL          GNU General Public License
#GUI          Graphical User Interface
#HTML         HyperText Markup Language
#IANAL        I am not a lawyer (but)
#IE           Internet Explorer
#IIRC         If I remember correctly
#IMHO         In my humble opinion
#IMO          In my opinion
#IOW          In other words
#IRC          Internet Relay Chat
#IRL          In real life
#KISS         Keep it simple stupid
#LAN          Local Area Network
#LGPL         GNU Lesser General Public License
#LOL          Laughing out loud
#MathML       Mathematical Markup Language
#MB           Megabyte
#MHz          Megahertz
#MSIE         Microsoft Internet Explorer
#OMG          Oh my God
#OS           Operating System
#OSS          Open Source Software
#OTOH         On the other hand
#PITA         Pain in the Ass
#RFC          Request for Comments
#ROTFL        Rolling on the floor laughing
#RTFM         Read The Fine Manual
#spec         specification
#TIA          Thanks in advance
#TL;DR        Too long; didn't read
#TOC          Table of Contents
#URI          Uniform Resource Identifier
#URL          Uniform Resource Locator
#W3C          World Wide Web Consortium
#WTF?         What the f***
#WYSIWYG      What You See Is What You Get
#YMMV         Your mileage may vary

자동 변환 문자열 비활성화

#<->     ↔
#->      →
#<-      ←
#<=>     ⇔
#=>      ⇒
#<=      ⇐
#>>      »
#<<      «
#---     —
#--      –
#(c)     ©
#(tm)    ™
#(r)     ®
#...     …

Interwiki 설정

# Custom links
instagram https://www.instagram.com/{NAME}/
threads   https://www.threads.com/{NAME}
namu      https://namu.wiki/w/{NAME}
ue        https://unicode-explorer.com/{NAME}
4)

favicon 설정

  • apple-touch-icon.png
  • favicon.ico
  • favicon.svg
  • favicon-96x96.png

function tpl_favicon($types = array('favicon')) {

    $return = '';

    /*
    foreach($types as $type) {
        switch($type) {
            case 'favicon':
                $look = array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico');
                $return .= '<link rel="shortcut icon" href="'.tpl_getMediaFile($look).'" />'.NL;
                break;
            case 'mobile':
                $look = array(':wiki:apple-touch-icon.png', ':apple-touch-icon.png', 'images/apple-touch-icon.png');
                $return .= '<link rel="apple-touch-icon" href="'.tpl_getMediaFile($look).'" />'.NL;
                break;
            case 'generic':
                // ideal world solution, which doesn't work in any browser yet
                $look = array(':wiki:favicon.svg', ':favicon.svg', 'images/favicon.svg');
                $return .= '<link rel="icon" href="'.tpl_getMediaFile($look).'" type="image/svg+xml" />'.NL;
                break;
        }
    }
    */
    $return .= '<link rel="icon" type="image/png" href="https://wiki.jobdeveloper.co.kr/favicon-96x96.png" sizes="96x96" />'.NL;
    $return .= '<link rel="icon" type="image/svg+xml" href="https://wiki.jobdeveloper.co.kr/favicon.svg" />'.NL;
    $return .= '<link rel="shortcut icon" href="https://wiki.jobdeveloper.co.kr/favicon.ico" />'.NL;
    $return .= '<link rel="apple-touch-icon" sizes="180x180" href="https://wiki.jobdeveloper.co.kr/apple-touch-icon.png" />'.NL;

    return $return;
}

manifest 설정

  • web-app-manifest-192x192.png
  • web-app-manifest-512x512.png

{
	"name": "잡개발자 리토의 잡위키",
	"short_name": "잡개발자",
	"icons": [
	{
		"src": "/web-app-manifest-192x192.png",
		"sizes": "192x192",
		"type": "image/png",
		"purpose": "maskable"
	},
	{
		"src": "/web-app-manifest-512x512.png",
		"sizes": "512x512",
		"type": "image/png",
		"purpose": "maskable"
	}
	],
	"theme_color": "#333333",
	"background_color": "#333333",
	"display": "standalone",
	"start_url": "/"
}

    if (actionOK('manifest')) {
        $head['link'][] = array('rel'=> 'manifest', 'href'=> DOKU_BASE.'site.webmanifest');
    }

start 문서 index,follow 설정

    if(($ACT == 'show' || $ACT == 'export_xhtml') && !$REV) {
        if($INFO['exists']) {
            //delay indexing:
            if((time() - $INFO['lastmod']) >= $conf['indexdelay'] && ($ID === $conf['start'] || !isHiddenPage($ID))) {
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
            } else {
                $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
            }
            $canonicalUrl = wl($ID, '', true, '&');
            if ($ID == $conf['start']) {
                $canonicalUrl = DOKU_URL;
            }
            $head['link'][] = array('rel'=> 'canonical', 'href'=> $canonicalUrl);
        } else {
            $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,follow');
        }
    } elseif(defined('DOKU_MEDIADETAIL')) {
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'index,follow');
    } else {
        $head['meta'][] = array('name'=> 'robots', 'content'=> 'noindex,nofollow');
    }

사이트맵 한글 정렬 개선

    if (!empty($sort)) {
        if ($sort == 'date') {
            @array_multisort(array_map('filemtime', $filepaths), SORT_NUMERIC, SORT_DESC, $files);
        } else /* natural */ {
            asort($files);
        }
        asort($dirs);
    }

검색어 하이라이트 개선

function html_show($txt=null){
    global $ID;
    global $REV;
    global $HIGH;
    global $INFO;
    global $DATE_AT;
    //disable section editing for old revisions or in preview
    if($txt || $REV){
        $secedit = false;
    }else{
        $secedit = true;
    }

    if (!is_null($txt)){
        //PreviewHeader
        echo '<br id="scroll__here" />';
        echo p_locale_xhtml('preview');
        echo '<div class="preview"><div class="pad">';
        $html = html_secedit(p_render('xhtml',p_get_instructions($txt),$info),$secedit);
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
        echo $html;
        echo '<div class="clearer"></div>';
        echo '</div></div>';

    }else{
        if ($REV||$DATE_AT){
            $data = array('rev' => &$REV, 'date_at' => &$DATE_AT);
            Event::createAndTrigger('HTML_SHOWREV_OUTPUT', $data, 'html_showrev');
        }
        $html = p_wiki_xhtml($ID,$REV,true,$DATE_AT);
        $html = html_secedit($html,$secedit);
        if($INFO['prependTOC']) $html = tpl_toc(true).$html;
        //$html = html_hilight($html,$HIGH);
        echo $html;
    }
}

jQuery(function() {
	// 검색어 파라미터
	var phrases = [];
	var search = window.location.search;
	if (search) {
		var params = search.substring(1).split('&');
		for (var i = 0; i < params.length; i++) {
			var pair = params[i].split('=');
			var key = decodeURIComponent(pair[0]);
			if (key === 's[]' && pair[1]) {
				var value = decodeURIComponent(pair[1].replace(/\+/g, ' '));
				phrases.push(value);
			}
		}
	}
	if (phrases.length === 0) return;

	// 검색어 정규식
	var escaped = [];
	for (var j = 0; j < phrases.length; j++) {
		escaped.push(phrases[j].replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'));
	}
	var regex = new RegExp('(' + escaped.join('|') + ')', 'gi');

	// 제외 리스트
	var exclude_list = [
		'div.syntaxhighlighter'					// SyntaxHighlighter4 Plugin
		, '[id^="plant-uml-diagram-"]'			// PlantUML Parser Plugin
		, 'div.tags span a'						// Tag Plugin
	];
	var exclude_selector = exclude_list.join(', ');

	// 허용 리스트
	var allow_list = [
		'br', 'wbr'
		, 'header', 'footer'
		, 'main', 'section', 'article', 'aside'
		, 'nav', 'address'
		, 'div', 'p', 'span'
		, 'hgroup', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
		, 'ul', 'ol', 'li', 'dl', 'dt', 'dd'
		, 'menu', 'label', 'hr'
		, 'table', 'thead', 'tbody', 'tfoot', 'th', 'tr', 'td', 'caption'
		, 'a', 'b', 'i', 'q', 's', 'u'
		, 'blockquote', 'figure', 'figcaption', 'details', 'summary'
		, 'abbr', 'cite', 'code', 'data', 'del', 'dfn', 'em', 'ins', 'kbd', 'mark', 'samp', 'small', 'strong', 'sub', 'sup', 'time', 'var'
		, 'ruby', 'rp', 'rt', 'bdo', 'bdi'
		, 'acronym', 'big', 'center', 'dir', 'font', 'marquee', 'nobr', 'plaintext', 'rb', 'rbc', 'rtc', 'selectedcontent', 'strike', 'tt', 'xmp'
	];

	// 하이라이트 함수
	function html_hilight($node) {
		$node.contents().each(function() {
			var node = this;
			if (node.nodeType === 3) {
				var txt = node.nodeValue;
				if (regex.test(txt)) {
					regex.lastIndex = 0;
					jQuery(node).replaceWith(txt.replace(regex, '<span class="search_hit">$1</span>'));
				}
			} else if (node.nodeType === 1) {
				var $this = jQuery(node);
				if (!$this.is(exclude_selector)) {
					var tag = node.tagName.toLowerCase();
					if (allow_list.indexOf(tag) !== -1) {
						html_hilight($this);
					}
				}
			}
		});
	}

	// 하이라이트 함수 실행
	var $target = jQuery("div.page.group");
	if ($target.length > 0) {
		html_hilight($target);
	}
});

SEO 개선

  • logo.png

<!-- Open Graph -->
<meta property="og:type" content="website" />
<meta property="og:site_name" content="잡개발자 리토의 잡위키" />
<meta property="og:url" content="https://wiki.jobdeveloper.co.kr/" />
<meta property="og:image" content="https://wiki.jobdeveloper.co.kr/logo.png" />
<!-- //Open Graph -->

<!-- JSON-LD -->
<script type="application/ld+json">
{
	"@context": "https://schema.org",
	"@graph": [
		{
			"@type": "Organization",
			"@id": "https://wiki.jobdeveloper.co.kr/#organization",
			"name": "잡개발자 리토의 잡위키",
			"url": "https://wiki.jobdeveloper.co.kr/",
			"logo": {
				"@type": "ImageObject",
				"url": "https://wiki.jobdeveloper.co.kr/logo.png"
			},
			"image": {
				"@type": "ImageObject",
				"url": "https://wiki.jobdeveloper.co.kr/logo.png"
			}
		},
		{
			"@type": "WebSite",
			"@id": "https://wiki.jobdeveloper.co.kr/#website",
			"name": "잡개발자 리토의 잡위키",
			"url": "https://wiki.jobdeveloper.co.kr/",
			"publisher": {
				"@id": "https://wiki.jobdeveloper.co.kr/#organization"
			},
			"potentialAction": {
				"@type": "SearchAction",
				"target": "https://wiki.jobdeveloper.co.kr/doku.php?do=search&q={search_term_string}",
				"query-input": "required name=search_term_string"
			}
		}
	]
}
</script>
<!-- //JSON-LD -->

User-agent: *
Allow: /

Sitemap: https://wiki.jobdeveloper.co.kr/doku.php?do=sitemap

    // 수정일 메타 데이터
    $head['meta'][] = array('name'=> 'revised', 'content'=> date_iso8601($INFO['lastmod']));
    $head['meta'][] = array('property'=> 'article:modified_time', 'content'=> date_iso8601($INFO['lastmod']));

        default : // SHOW and anything else not included
            $page_title = $name;

            // 이름공간 정보 표기
            global $INFO;
            if (!empty($INFO['namespace'])) {
                $page_title .= ' | ' . str_replace(':', ' > ', $INFO['namespace']);
            }

카카오애드핏

<!-- 카카오애드핏 -->
<style>
.ad-adfit-pc {
	display: none;
}

.ad-adfit-mobile {
	display: none;
}

@media screen and (min-width: 801px) {
	.ad-adfit-pc {
		display: block;
	}

	.ad-adfit-mobile {
		display: none;
	}
}

@media screen and (max-width: 800px) {
	.ad-adfit-pc {
		display: none;
	}

	.ad-adfit-mobile {
		display: block;
	}
}
</style>
<script type="text/javascript" src="//t1.daumcdn.net/kas/static/ba.min.js" async></script>
<!-- //카카오애드핏 -->

<!-- 카카오애드핏 -->
<div class="ad-adfit-mobile">
	<ins class="kakao_ad_area" style="display:none;"
	data-ad-unit = "DAN-uCoX3Nv9fPaiC2mH"
	data-ad-width = "320"
	data-ad-height = "100"></ins>
</div>
<!-- //카카오애드핏 -->

<!-- 카카오애드핏 -->
<div class="ad-adfit-pc">
	<ins class="kakao_ad_area" style="display:none;"
	data-ad-unit = "DAN-n9YTFT0FiNdcCyWi"
	data-ad-width = "728"
	data-ad-height = "90"></ins>
</div>
<div class="ad-adfit-mobile">
	<ins class="kakao_ad_area" style="display:none;"
	data-ad-unit = "DAN-zlwD249GnskVdX8E"
	data-ad-width = "320"
	data-ad-height = "100"></ins>
</div>
<!-- //카카오애드핏 -->

추적 코드

<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-CYCM0MXQLG"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  gtag('config', 'G-CYCM0MXQLG');
</script>

<!-- Clarity tracking code -->
<script type="text/javascript">
    (function(c,l,a,r,i,t,y){
        c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
        t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
        y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
    })(window, document, "clarity", "script", "tfjwj8ecxc");
</script>

플러그인

IndexMenu Plugin

{{indexmenu>:#1|js#simple navbar nomenu notoc}}

5)

Note Plugin

.plugin_note {
  margin: 2em auto;
  max-width: 90%;
  min-height: 40px;
  text-align: justify;
  vertical-align: middle;
  border-collapse: collapse;
  padding: 15px 20px 15px 80px;
  background-position: 20px 50%;
  background-repeat: no-repeat;
  -moz-border-radius: 20px;
  -khtml-border-radius: 20px;
  border-radius: 20px;
  color: black;
  overflow: hidden;
}

PlantUML Parser Plugin

[id^="plant-uml-diagram-"] {
	overflow: auto;
}

        if($data['include_links'] == "1") {
            $renderer->doc .= "<div id=\"plantumlparse_link_section\">";
            /*
            $renderer->doc .= "<a target='_blank' href='".$data['url']['svg']."'>SVG</a> | ";
            $renderer->doc .= "<a target='_blank' href='".$data['url']['png']."'>PNG</a> | ";
            $renderer->doc .= "<a target='_blank' href='".$data['url']['txt']."'>TXT</a>";
            */
            $renderer->doc .= "<a target='_blank' href='".$data['url']['svg']."'>SVG</a> | ";
            $renderer->doc .= "<a target='_blank' href='".$data['url']['png']."'>PNG</a>";
            $renderer->doc .= "</div>";
        }

Tag Plugin

.dokuwiki div.tags {
  /*border-top: 2px dotted __border__;*/
  clear: both;
  /*margin-bottom: 1.4em;*/
}

.dokuwiki div.tagstop {
  /*border-bottom: 2px dotted __border__;
  margin-top: -1.3em;
  margin-bottom: .4em;*/
}

.dokuwiki div.tags span a,
.dokuwiki div.tagstop span a {
	color: #2962ff;
	background-color: #e3f2fd;
	padding: 4px 4px;
	border-radius: 4px;
}

    public function tagLinks($tags) {
        if (empty($tags) || ($tags[0] == '')) {
            return '';
        }

        $links = array();
        foreach ($tags as $tag) {
            $links[] = $this->tagLink($tag);
        }
        return implode('&nbsp;'.DOKU_LF.DOKU_TAB, $links);
    }

관리

템플릿 스타일 설정

__site_width__ = "1330px"
__sidebar_width__ = "16em"
__tablet_width__ = "800px"
__phone_width__ = "480px"
__theme_color__ = "#333333"
6)

환경 설정 > 보이기

이동 경로 추적 비활성화

$conf['breadcrumbs'] = 0;

타이포그래피 대체 비활성화

$conf['typography'] = '0';

목차의 최대 단계 비활성화

$conf['maxtoclevel'] = '0';

문단의 최대 편집 단계 비활성화

$conf['maxseclevel'] = '0';

문서 이름을 첫 문단 제목으로 사용

$conf['useheading'] = '1';

이름공간 읽기 권한 설정

$conf['sneaky_index'] = 1;

문서 숨기기 설정

$conf['hidepages'] = '(start|sidebar)';

환경 설정 > 인증

접근 제어 목록 (ACL) 사용

$conf['useacl'] = 1;

슈퍼유저 설정

$conf['superuser'] = '@admin';

도쿠위키 동작 비활성화

$conf['disableactions'] = 'backlink,recent,register';

환경 설정 > 스팸 방지

색인 전 지연 시간 (초)

$conf['indexdelay'] = 0;

환경 설정 > 링크

링크에 대한 타겟 창

$conf['target']['interwiki'] = '_blank';
$conf['target']['extern'] = '_blank';

환경 설정 > 신디케이션 (RSS)

사이트맵 생성 날짜 빈도 (일)

$conf['sitemap'] = 1;

환경 설정 > 고급

업데이트와 보안 경고 비활성화

$conf['updatecheck'] = 0;

멋진 URL 사용

$conf['userewrite'] = '2';

존재하지 않는 문서 404 상태 코드 반환

$conf['send404'] = 1;

환경 설정 > Feature Flags

defer_js 비활성화

$conf['defer_js'] = 0;
7)

2)
2글자만 존재하는 경우 사라지는 버그 있음
3)
로그 경로: /data/cache/loglog.log
4)
이미지 경로: /lib/images/interwiki
5)
/doku.php?id=sidebar 또는 /doku.php/sidebar
6)
최소 해상도 1366px 기준 (스크롤바 제외 1330px)
7)
Indexmenu Plugin: If you use the 'js'-option of the indexmenu plugin, you have to disable the 'defer_js'-setting. This setting is temporary, in the future the indexmenu plugin will be improved.