글쓰기 시 링크 넣었을 때 오픈그래프 메타태그 넣어주기 (CKEditor4 전용, 스압!!)
meanI
112.♡.169.220
2024-09-25 10:27
585
1
1
-
- 첨부파일 : opengraphparser.zip (4.3K) - 다운로드
본문
안녕하세요.
항상 이윰빌더를 감사하게 사용하고 있는 유저입니다.
이번에는 게시판에서 글을 작성할 때 링크를 넣으면 해당 링크의 오픈그래프 메타데이터를 파악해 텍스트 형식의 링크가 카드 형식으로 나타나도록 하는 방법을 알려드리겠습니다.
'이번에는' 이라고 할만큼 뭘 올리진 않았지만...ㅎㅎ
![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227051.78003.png) 이렇게 입력하거나 주소를 붙여넣으면 ![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227056.92289.png) 이렇게 표시 된답니다\~ ### 주의사항 내지 버그 1. 일단은 텍스트 정렬이 가능하게끔 만들어두기는 했는데, 링크 삽입 후 텍스트 정렬하면 레이아웃이 깨집니다. 링크 삽입 전 정렬을 정해놓고 삽입하면 됩니다. 2. 비동기 코드로 작동하기 때문에 텍스트 입력 커서가 원하는대로 작동하지 않을 수 있습니다. 3. 어째서인지 table 안에다가 집어넣으면 table의 너비를 무시하고 비대해지는 문제가 있습니다. (table 스타일에 table-layout:fixed; width: 고정값으로 넣으시면 커지진 않지만 입력 안하면 그냥 커집니다.) 4. 저의 서버 환경 기준 자기 자신의 도메인 주소를 넣으면 오픈그래프 태그가 있어도 정보를 못 받아옵니다. 5. 카드링크 형식으로 넣을지 말지를 판단할 수가 없습니다. 그냥 오픈그래프 메타태그가 있으면 다 변환해줍니다. 이를 해결하기 위해서는 주소가 행의 처음으로 입력되어 있으면 통으로 변환하고 그게 아니면 다음줄에다가 카드링크를 넣어주도록 하는 방법이 있을 것 같습니다. 먼저 앞서 준비물이 필요합니다. ### 준비물 1. 이윰빌더용 CKEditor4 편집기 플러그인 (4.24 이상이어야 하는 것 같습니다. 저의 경우 4.22.1인데 최신 버전에서 호환성 문제 있는 기능들 짜맞춰가지고 어찌저찌 굴러는 갑니다.) 2. CKEditor4 Auto Link 플러그인: [https://ckeditor.com/cke4/addon/autolink](https://ckeditor.com/cke4/addon/autolink)
CKEditor4 기본 코드 자체에 Auto Link가 포함되어 있을 수 있습니다만, 본 방법은 해당 플러그인을 수정해서 사용하는 것이므로 별도로 다운로드하여 설치해야 합니다. 플러그인 설치 위치: `/plugin/editor/ckeditor4_eyoom[CKEditor4_편집기_플러그인_위치]/plugins/autolink` ### 오픈그래프 파싱용 php 파일 작성 (이하 오픈그래프 파서) 우선 오픈그래프를 파싱하기 위한 php 파일을 작성합니다. 자바스크립트 내에서는 다른 사이트의 정보를 받아서 html 코드를 분석하는 것이 제한적이기 때문에, 백엔드에서 처리해서 보내주는 편이 낫습니다. 라고 ChatGPT가 그랬습니다. 첨부파일에 올려드릴테니 그대로 사용하셔도 됩니다. 첨부파일은 `opengraphparser.zip`의 `opengraphparser.php`입니다. 그대로 사용하시는 경우 압축 풀어 `/page/opengraphparser.php`로 저장해주세요. ```php <?php include_once('../common.php'); if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가 if ($_SERVER['REQUEST_METHOD'] === 'POST') { $inputData = file_get_contents('php://input'); $data = json_decode($inputData, true); $url = $data['url']; } else if (php_sapi_name() ==='cli') { $url = $_SERVER['argv'][1]; } else { echo json_encode(['error'=>'Invalid request method']); exit(); } if (filter_var($url, FILTER_VALIDATE_URL)) { $options = [ 'http' => [ 'method' => 'GET', 'follow_location' => 1, 'max_redirects' => 10, 'header' => "User-Agent: PHP\r\n" ] ]; $context = stream_context_create($options); $html = file_get_contents($url, false, $context); if ($html !== false) { $doc = new DOMDocument(); @$doc->loadHTML($html); $metadata = []; $tags = $doc->getElementsByTagName('meta'); foreach ($tags as $tag) { if ($tag->hasAttribute('property') && strpos($tag->getAttribute('property'), 'og:') === 0) { $property = $tag->getAttribute('property'); $content = $tag->getAttribute('content'); $metadata[$property] = $content; } } header('Content-Type: application/json'); echo json_encode($metadata, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } else { echo json_encode(['error' => 'Unable to retrieve content from URL']); } } else { echo json_encode(['error'=>'Invalid URL']); } ?> ``` #### 코드 설명 우선 이 코드는 POST 요청과 터미널 상에서 실행하는 것 모두를 상정하고 만들었습니다. POST 요청의 경우 Fetch API나 AJAX 통신으로 POST 요청 받은 경우 JSON 데이터를 통해 파라미터(url)을 받으면 여기에서 사이트를 다운로드해 메타태크를 분석합니다. 터미널 상에서 실행하면 매개변수에 주소를 입력하면 됩니다. 사이트에 리다이렉트가 있을 수 있는 부분도 상정하여 `stream_context_create()` 함수를 사용하였습니다. (고마워요 ChatGPT) `$html` 변수에 다운로드 받은 사이트를 담고 DOMDocument() 클래스를 사용해 html 문서를 파싱합니다. 사이트에서 `meta` 태그를 모두 `$tags` 배열 변수에 담은 다음, 반복문을 이용하여 `property` 속성이 있는지, `property` 속성의 내용이 `og:`로 시작하는지 확인하여 해당 태그의 `property`명을 키로, 해당 태그의 `content`를 값으로 하여 `$metadata` 배열 변수에 담습니다. 그리고 `$metadata` 변수를 json으로 인코딩하여 출력합니다. ### CKEditor4 Auto Link 플러그인 수정 `opengraphparser.zip`의 `plugin.js` 파일입니다. 최신 버전(작성 기준 4.24.0)을 다운로드 받으셨으면 그냥 첨부파일 그대로 대체하셔도 됩니다. 전체 코드를 본문에 넣으려고 했으나 내용이 길어져 그냥 첨부파일을 참조해 주시길 바랍니다. #### 핵심 함수 `function checkOpengraph ( text )` 우선 가장 중요한 `function checkOpengraph ( text )`를 살펴봅시다. (99번째 줄부터) 쓸데없이 줄이 많은데요, 별 건 없습니다. 100번째 줄 ```javascript const url = "/page/opengraphparser.php"; ``` 오픈그래프 파서의 주소를 지정해줍니다. 파일을 다른 곳에 저장한 경우, 이 부분을 수정해주시면 됩니다. 102번째 \~ 108번째 줄 ```javascript return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({url: text}) }) ``` `url`에 POST 요청을 보냅니다. 보내는 내용은 `url: text`이며 이를 json 인코딩하여 같이 보냅니다. `text`는 `checkOpengraph` 함수 호출 시 입력되는 파라미터입니다. 109번째 줄 ```javascript .then(response => response.json()) ``` POST 응답을 받아 json으로 리턴합니다. 110번째 \~ 112번째 줄 ```javascript .then(result => { if (typeof(result.error) === 'string' || !result.hasOwnProperty('og:image') || !result.hasOwnProperty('og:title')) { console.log(result); } else { ``` json 변환된 결과를 `result`로 하여 처리합니다. `result`에 `error`라는 값이 있고 값이 `string`이거나 (없으면 `undefined`겠죠?) `result`에 `og:image`나 `og:title` 속성이 없으면 `result`만 콘솔에 출력하고 코드 실행을 끝냅니다. 114번째\~168번째 줄 코드가 너무 길어서 생략합니다. 1. 응답 받은 값에 주소가 있거나 없으면 파라미터로 제시한 원래 url로부터 hostname을 변수에 저장 2. 컨테이너가 될 span 요소와 그 내부를 이루는 요소를 정의하고 클래스와 속성, 내용 저장 3. 컨테이너 내부는 수정될 수 없도록 `contenteditable` 속성을 `false`로 지정 169번째 줄 ```javascript return `
![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227051.78003.png) 이렇게 입력하거나 주소를 붙여넣으면 ![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227056.92289.png) 이렇게 표시 된답니다\~ ### 주의사항 내지 버그 1. 일단은 텍스트 정렬이 가능하게끔 만들어두기는 했는데, 링크 삽입 후 텍스트 정렬하면 레이아웃이 깨집니다. 링크 삽입 전 정렬을 정해놓고 삽입하면 됩니다. 2. 비동기 코드로 작동하기 때문에 텍스트 입력 커서가 원하는대로 작동하지 않을 수 있습니다. 3. 어째서인지 table 안에다가 집어넣으면 table의 너비를 무시하고 비대해지는 문제가 있습니다. (table 스타일에 table-layout:fixed; width: 고정값으로 넣으시면 커지진 않지만 입력 안하면 그냥 커집니다.) 4. 저의 서버 환경 기준 자기 자신의 도메인 주소를 넣으면 오픈그래프 태그가 있어도 정보를 못 받아옵니다. 5. 카드링크 형식으로 넣을지 말지를 판단할 수가 없습니다. 그냥 오픈그래프 메타태그가 있으면 다 변환해줍니다. 이를 해결하기 위해서는 주소가 행의 처음으로 입력되어 있으면 통으로 변환하고 그게 아니면 다음줄에다가 카드링크를 넣어주도록 하는 방법이 있을 것 같습니다. 먼저 앞서 준비물이 필요합니다. ### 준비물 1. 이윰빌더용 CKEditor4 편집기 플러그인 (4.24 이상이어야 하는 것 같습니다. 저의 경우 4.22.1인데 최신 버전에서 호환성 문제 있는 기능들 짜맞춰가지고 어찌저찌 굴러는 갑니다.) 2. CKEditor4 Auto Link 플러그인: [https://ckeditor.com/cke4/addon/autolink](https://ckeditor.com/cke4/addon/autolink)
CKEditor4 기본 코드 자체에 Auto Link가 포함되어 있을 수 있습니다만, 본 방법은 해당 플러그인을 수정해서 사용하는 것이므로 별도로 다운로드하여 설치해야 합니다. 플러그인 설치 위치: `/plugin/editor/ckeditor4_eyoom[CKEditor4_편집기_플러그인_위치]/plugins/autolink` ### 오픈그래프 파싱용 php 파일 작성 (이하 오픈그래프 파서) 우선 오픈그래프를 파싱하기 위한 php 파일을 작성합니다. 자바스크립트 내에서는 다른 사이트의 정보를 받아서 html 코드를 분석하는 것이 제한적이기 때문에, 백엔드에서 처리해서 보내주는 편이 낫습니다. 라고 ChatGPT가 그랬습니다. 첨부파일에 올려드릴테니 그대로 사용하셔도 됩니다. 첨부파일은 `opengraphparser.zip`의 `opengraphparser.php`입니다. 그대로 사용하시는 경우 압축 풀어 `/page/opengraphparser.php`로 저장해주세요. ```php <?php include_once('../common.php'); if (!defined('_GNUBOARD_')) exit; // 개별 페이지 접근 불가 if ($_SERVER['REQUEST_METHOD'] === 'POST') { $inputData = file_get_contents('php://input'); $data = json_decode($inputData, true); $url = $data['url']; } else if (php_sapi_name() ==='cli') { $url = $_SERVER['argv'][1]; } else { echo json_encode(['error'=>'Invalid request method']); exit(); } if (filter_var($url, FILTER_VALIDATE_URL)) { $options = [ 'http' => [ 'method' => 'GET', 'follow_location' => 1, 'max_redirects' => 10, 'header' => "User-Agent: PHP\r\n" ] ]; $context = stream_context_create($options); $html = file_get_contents($url, false, $context); if ($html !== false) { $doc = new DOMDocument(); @$doc->loadHTML($html); $metadata = []; $tags = $doc->getElementsByTagName('meta'); foreach ($tags as $tag) { if ($tag->hasAttribute('property') && strpos($tag->getAttribute('property'), 'og:') === 0) { $property = $tag->getAttribute('property'); $content = $tag->getAttribute('content'); $metadata[$property] = $content; } } header('Content-Type: application/json'); echo json_encode($metadata, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); } else { echo json_encode(['error' => 'Unable to retrieve content from URL']); } } else { echo json_encode(['error'=>'Invalid URL']); } ?> ``` #### 코드 설명 우선 이 코드는 POST 요청과 터미널 상에서 실행하는 것 모두를 상정하고 만들었습니다. POST 요청의 경우 Fetch API나 AJAX 통신으로 POST 요청 받은 경우 JSON 데이터를 통해 파라미터(url)을 받으면 여기에서 사이트를 다운로드해 메타태크를 분석합니다. 터미널 상에서 실행하면 매개변수에 주소를 입력하면 됩니다. 사이트에 리다이렉트가 있을 수 있는 부분도 상정하여 `stream_context_create()` 함수를 사용하였습니다. (고마워요 ChatGPT) `$html` 변수에 다운로드 받은 사이트를 담고 DOMDocument() 클래스를 사용해 html 문서를 파싱합니다. 사이트에서 `meta` 태그를 모두 `$tags` 배열 변수에 담은 다음, 반복문을 이용하여 `property` 속성이 있는지, `property` 속성의 내용이 `og:`로 시작하는지 확인하여 해당 태그의 `property`명을 키로, 해당 태그의 `content`를 값으로 하여 `$metadata` 배열 변수에 담습니다. 그리고 `$metadata` 변수를 json으로 인코딩하여 출력합니다. ### CKEditor4 Auto Link 플러그인 수정 `opengraphparser.zip`의 `plugin.js` 파일입니다. 최신 버전(작성 기준 4.24.0)을 다운로드 받으셨으면 그냥 첨부파일 그대로 대체하셔도 됩니다. 전체 코드를 본문에 넣으려고 했으나 내용이 길어져 그냥 첨부파일을 참조해 주시길 바랍니다. #### 핵심 함수 `function checkOpengraph ( text )` 우선 가장 중요한 `function checkOpengraph ( text )`를 살펴봅시다. (99번째 줄부터) 쓸데없이 줄이 많은데요, 별 건 없습니다. 100번째 줄 ```javascript const url = "/page/opengraphparser.php"; ``` 오픈그래프 파서의 주소를 지정해줍니다. 파일을 다른 곳에 저장한 경우, 이 부분을 수정해주시면 됩니다. 102번째 \~ 108번째 줄 ```javascript return fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({url: text}) }) ``` `url`에 POST 요청을 보냅니다. 보내는 내용은 `url: text`이며 이를 json 인코딩하여 같이 보냅니다. `text`는 `checkOpengraph` 함수 호출 시 입력되는 파라미터입니다. 109번째 줄 ```javascript .then(response => response.json()) ``` POST 응답을 받아 json으로 리턴합니다. 110번째 \~ 112번째 줄 ```javascript .then(result => { if (typeof(result.error) === 'string' || !result.hasOwnProperty('og:image') || !result.hasOwnProperty('og:title')) { console.log(result); } else { ``` json 변환된 결과를 `result`로 하여 처리합니다. `result`에 `error`라는 값이 있고 값이 `string`이거나 (없으면 `undefined`겠죠?) `result`에 `og:image`나 `og:title` 속성이 없으면 `result`만 콘솔에 출력하고 코드 실행을 끝냅니다. 114번째\~168번째 줄 코드가 너무 길어서 생략합니다. 1. 응답 받은 값에 주소가 있거나 없으면 파라미터로 제시한 원래 url로부터 hostname을 변수에 저장 2. 컨테이너가 될 span 요소와 그 내부를 이루는 요소를 정의하고 클래스와 속성, 내용 저장 3. 컨테이너 내부는 수정될 수 없도록 `contenteditable` 속성을 `false`로 지정 169번째 줄 ```javascript return `
${ogLinkContainer.getOuterHtml()}
`; ``` 완성된 컨테이너의 html을 리턴합니다. 추후 텍스트 정렬을 위하여 p 태그로 한 번 감싸주고, 편집이 비교적 용이할 수 있도록 앞 뒤로 공백 문자를 삽입합니다. 172번째\~174번째 줄 ```javascript .catch(error => { console.log('Error: ', error); }); ``` POST 요청이 실패할 경우 오류를 표시합니다. #### 붙여넣기 동작 시 작동할 코드 (23번째 줄) 자 이제 붙여넣기 시 실제로 함수가 작동하도록 해야 합니다. 원래는 코드 속에 아래 내용만 있었는데 이를 수정해야 합니다. ```javascript var data = evt.data.dataValue; // If we found "<" it means that most likely there's some tag and we don't want to touch it. if ( data.indexOf( '<' ) > -1 ) { return; } if ( matchLink( data ) ) { evt.data.dataValue = getHtmlToInsert( data ); evt.data.type = 'html'; } ``` 35번째\~37번째 줄 ```javascript if ( matchLink( data ) ) { evt.data.dataValue = getHtmlToInsert(data); evt.data.type = 'html'; ``` (원본과 동일한 부분입니다) 붙여넣은 데이터가 주소 형식을 하고 있으면, 우선 일반적인 붙여넣기 작업을 실행합니다. 39번째\~41번째 줄 ```javascript checkOpengraph(data).then((returnedData) => { if (!returnedData) return; var matched = CKEDITOR.plugins.textMatch.match (editor.getSelection().getRanges()[0], matchCallback); ``` `checkOpengraph()` 함수에 `data`를 매개변수로 입력해 호출합니다. 코드는 비동기적으로 작동하기 때문에 `.then()`으로 코드 수행이 완료된 이후 작동하도록 했습니다. 어쨌든 응답 값이 없으면 함수 실행을 그만두고, 있으면 붙여넣은 부분이 주소 형식에 맞는지 콜백 함수를 실행해 판단하고 `matched` 변수에 저장합니다. 43번째\~46번째 줄 ```javascript if (matched) { var selection = editor.getSelection(); selection.selectRanges( [ matched.range ] ); editor.insertHtml(returnedData); ``` `matched`에 내용이 있으면 (주소 형식인지 검사한 결과값) 주소가 입력된 범위만큼을 선택해 `checkOpengraph()`함수가 실행된 결과값(`returnedData`)로 대체합니다. 48번째\~56번째 줄 원본 코드의 다른 부분에 있던 내용인데, 붙여넣기 완료하면 커서를 끝으로 옮기는 기능일겁니다. #### 주소 직접 입력 시 작동할 코드 `if (matched)`안에 있는 내용만 수정되었는데 붙여넣기에 넣은 코드와 거의 동일합니다. 순서가 약간 다르네요. 69번째\~73번째 줄 ```javascript checkOpengraph(matched.text).then((returnedData) => { if (!returnedData) { insertLink( matched ); return; } ``` `checkOpengraph()`함수에 `matched.text`를 파라미터로 담아 호출합니다. matched.text는 바로 이전 줄에서 **입력한 텍스트에서 주소 형식이 있는지 판단해 저장한 변수의 검출 값입니다(주소 부분)**. 오픈그래프 파서 결과를 리턴 받지 못했으면 `insertLink ( matched )`함수를 실행하고 코드를 종료합니다. (일반적인 주소 링크 형태로 변환) 그 외 부분인 75번째 \~ 87번째 줄은 43번째\~56번째 줄과 동일합니다. ### 카드링크 박스 꾸미기 (CSS) 이대로 저장하고 주소를 편집기에 넣어보시면 잠시 후 링크가 대체되어 나올겁니다. ![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227066.8308.png) 오픈그래프에 지정한 이미지 크기에 따라 이미지 크기는 크게 나올 수 있습니다. 총 두개의 css 파일을 수정해야 합니다. 하나는 CKEditor4에서 사용될 css 파일이고, 하나는 게시글 등록 후에 사용될 css 파일입니다. 먼저 CKEditor4에서 사용될 css 파일 위치는 `/plugin/editor/ckeditor4_eyoom[CKEditor4_편집기_플러그인_위치]/contents.css`입니다. 첨부파일의 css 코드를 붙여넣어주시면 됩니다. 첨부파일은 `opengraphparser.zip`의 `opengraph.css`입니다. 다음으로는 게시글 등록 후에 사용될 css 파일을 편집하시면 되는데, css 파일로 직접 작업하셔도 되고, 관리자 페이지에서 **환경설정 > 기본환경설정 > 레이아웃 추가설정** 메뉴에 추가하셔도 됩니다. 레이아웃 추가설정 메뉴에서 작업하실 경우 \`script\` 태그로 감싸 사이에 넣어주셔야 합니다. css 파일로 작업하시는 경우, 테마 폴더의 css 파일을 수정하시면 됩니다. 기본 테마 사용하시는 경우 `/theme/eb4_basic/css/custom.css` 파일을 수정하시면 됩니다. 동일하게 첨부파일의 css 코드를 붙여넣어주시면 됩니다. 다 하고 나면...! ![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227072.56294.png) 이렇게 깔끔하게 나옵니다. 작성 완료하고 게시글을 볼 때에도 잘 나오죠. ![!\[image\]](https://eyoom.net/data/editor/2409/1888856540_1727227077.76406.png) 여기까지 읽어주셔서 감사합니다. 꽤나 노가다 있는 작업인데..ㅋㅋ 고생하셨습니다. 시간 되시면 저희 사이트도 둘러봐주세요\~ [https://b2b.soundcat.com/](https://b2b.soundcat.com/) 기본 테마를 뜯어고쳐서 만들었습니다. 다시 한 번 감사합니다!추천한 회원
NPIO-
[이윰빌더 시즌4] 게시판 업데이트 시 적용되는 것이었나보네요!ㅎㅎ2024-09-24
-
[이윰빌더 시즌4] 설치 완료 후 DB 업그레이드했는데 업그레이드 할 필요가 없다고 나오는군요. 예약기능때문에 테이블 수정이 필요할것 같은데 알아서 되는것일까요?2024-09-24
-
[이윰빌더 시즌4] 오 감사합니다. 예약 게시판은 직접 만들어서 운용하고 있었는데 기본 기능으로 가능할지 확인해봐야겠네요ㅎㅎ (그나저나 오늘 새로운 그누보드 버전이 나와버려서... 사소한 업데이트라 그냥 적용해도 될지는 모르겠네요ㅋㅋ)2024-09-24
-
[이윰빌더 시즌4] 아아ㅎ 기본 테마 사용중이긴 한데, 최근 대규모 패치에서 테마파일은 제외시켰었어요! 마개조를 많이 해놔서,, 감사합니다!2024-07-17
-
[팁 & 테크] 본문에는 자바스크립트쪽 코드가 잘려나와서 첨부파일로 참조해주시면 될것같습니다..ㅎㅎ2024-07-17
-
[팁 & 테크] php쪽에서 확인하는 방법이 잘 되지 않는다면 코드 참조하여 자바스크립트 이용, 클라이언트측에서 확인하도록 하는 방법도 있을 것 같습니다! AJAX 등을 이용해서 해당 깃허브 파일을 다운로드하고 비교하는 방법으로..2024-07-17
-
[팁 & 테크] 물론이죠!!ㅎㅎ2024-07-17
-
[이윰빌더 시즌4] 감사합니다! 패치로 진행을 해서 그런가... 버튼 스타일에 btn-e-navy가 없는지 버튼 배경색이 안나오네요ㅠ 다시 indigo로 바꿔서 잘 사용하겠습니다!2024-07-17
댓글목록1
NPIO님의 댓글
시간 날때 한번 꼼꼼히 살펴보도록 하겠습니다.
좋은 팁 공유해 주셔서 감사합니다.
오늘도 멋진 하루 되세요.
축하합니다. 첫댓글 포인트 8포인트를 획득하였습니다.