# codoc/0.8.6/class-codoc.php

codoc, version 0.8.6. 532 lines.

- Page: https://pluginprobe.com/plugins/codoc/0.8.6/code/class-codoc.php
- Raw: https://pluginprobe.com/plugins/codoc/0.8.6/raw/class-codoc.php
- Modified: 2020-02-02T17:00:12+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/codoc/0.8.6/code/class-codoc.php#L10-L20`.

```php
<?php

final class Codoc {

	public function __construct() {
		if (is_admin()) {
			// setting
			$this->add_settings();
		}
		$auth_info = get_option(CODOC_AUTHINFO_OPTION_NAME);
		if (!$auth_info) {
			return $this;
		}

		// データ同期 (save_postはis_adminで実行されないケースがある)
		add_action( 'save_post',        [$this,'save_post'], 20, 3 );
		add_action( 'added_post_meta',  [$this,'updated_post_meta'], 10, 3 );
		add_action( 'updated_post_meta',[$this,'updated_post_meta'], 10, 3 );
		add_action( 'deleted_post_meta',[$this,'deleted_post_meta'], 10, 4 );
		
		if (is_admin()) {
			// gutenberg
			require_once 'src/init.php';
			// tinymce
			$this->add_mce();
			add_action('wp_loaded', function() {
				wp_localize_script('wordpress-cgb-block-js', 'OPTIONS', array(
					'codoc_url'      => CODOC_URL,
					'codoc_usercode' => get_option(CODOC_USERCODE_OPTION_NAME),
                    'codoc_plugin_version' => CODOC_PLUGIN_VERSION,
                    'codoc_sdk_path'       => CODOC_SDK_PATH,
				));

				// tinymce 用
				//wp_enqueue_script( 'codoc-integration-js',	 CODOC_URL . '/js/integration.js', true );
			});
			return $this;
		}

		// codocのJS登録

		add_action( 'wp_enqueue_scripts', function() {
			wp_enqueue_script( 'codoc-injector-js',	 CODOC_URL . '/js/cms.js' );
		});
		// 登録したscriptタグに属性をつける
		add_filter('script_loader_tag', [$this,'modifier_script_tag'],10,2);
		// tinymce用のショートコード
		add_shortcode('codoc', [$this, 'injector_shortcode']);

		// paywall用の本文非表示化とcodocタグへの属性追加
		add_filter('the_content',[$this,'the_content']);
		return $this;
	}
	
	public function modifier_script_tag($tag,$handle) {
		if($handle !== 'codoc-injector-js') {
			return $tag;
		}
		$CODOC_SETTINGS = get_option(CODOC_SETTINGS_OPTION_NAME);
		$data_css = '';
		if ($css_path = $CODOC_SETTINGS['css_path']) {
			$data_css = sprintf(' data-css="%s" ',$css_path);
		}
        //return str_replace(' src=', $data_css . ' defer src=', $tag);
        return preg_replace('/(src=[^>]+)/',' ${1} ' . $data_css . ' defer',$tag);
	}
	public function injector_shortcode($atts) {
		global $post;
		ob_start();
		require 'views/codoc-injector.php';
		return ob_get_clean();
	}
	public function callAPI($method,$path,$body = [],$headers = []) {
		$usercode = get_option(CODOC_USERCODE_OPTION_NAME);
		$token    = get_option(CODOC_TOKEN_OPTION_NAME);

		$headers['X-CodocToken'] = $token;
		$host = CODOC_URL;
		$sslverify = true;

		if (preg_match('/local/',CODOC_URL)) {
			$sslverify = false;
			$host = 'https://host.docker.internal';
		}
		$url = sprintf("%s/api/v1/cms/%s%s",$host,$usercode,$path);
		$http = new WP_Http();
		try {
			$response = $http->request(
				$url,
				[
					'sslverify' => $sslverify,
					'method'  => $method,
					'timeout' => 10,
					'headers' => $headers,
					'body'    => $body,
				]
			);
			if ( is_wp_error($response) || $response['response']['code'] != 200 ) {
				//何もしない
				//var_dump( $response );
			}
		} catch(Exception $e) {
		}
		
		if (!is_wp_error($response) and
			isset($response['body']) and
			is_string($response['body']) and
			is_array(json_decode($response['body'], true)) and
			(json_last_error() == JSON_ERROR_NONE)) {
			return json_decode($response['body']);
		} else {
			return null;
		}
	}
	# settings / 設定関連
	public function add_settings() {
		global $CODOC_SETTINGS;
		add_action( 'admin_menu' ,function(){
			add_options_page(
				'codoc の設定',	   //ページタイトル
				'codoc',		   //設定メニューに表示されるメニュータイトル
				'edit_users',	   //権限
				'codoc',		   //設定ページのURL。options-general.php?page=codoc
				function() {
					echo '<div clas="wrap">';
					echo '<form method="post" action="options.php">';
					settings_fields( 'codoc_option_group' );
					do_settings_sections( 'codoc' );
					submit_button(); // 送信ボタン
					echo '</div>';
				}
			);
		});

		add_action( "admin_init", function() {
			// codocからの認証データ処理
			if (isset($_GET['page']) and $_GET['page'] == 'codoc' and isset($_GET['fetch_token_key'])) {
				$key = sanitize_text_field($_GET['fetch_token_key']);
				$usercode = sanitize_text_field($_GET['usercode']);
				update_option(CODOC_USERCODE_OPTION_NAME,$usercode);
				$data = $this->callAPI('GET','/token',[ "fetch_token_key" => $key ]);
				if ($data->status and $token = $data->token) {
					update_option(CODOC_TOKEN_OPTION_NAME,$token);
					$data = $this->callAPI('GET','');
					if ($data->status and $user = $data->user) {
						update_option(CODOC_AUTHINFO_OPTION_NAME,[
							'email' => $user->email,
							'name'  => $user->name,
						]);
					}
					#$current_url  = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
					#$current_url  = preg_replace('/(.*)fetch_token_key.*/','${1}&codoc_auth_finished=1',$current_url);
					//add_settings_error( 'general', 'settings_updated', __( 'OK' ), 'success' );
					$current_url  = admin_url('options-general.php') . '?page=codoc&codoc_auth_finished=1';
					
					wp_redirect( $current_url);
					exit;
				}
			}

			global $CODOC_USERCODE;
			global $CODOC_SETTINGS;
			global $CODOC_TOKEN;
			global $CODOC_AUTHINFO;
			$CODOC_USERCODE = get_option(CODOC_USERCODE_OPTION_NAME);
			$CODOC_SETTINGS = get_option(CODOC_SETTINGS_OPTION_NAME);
			$CODOC_TOKEN    = get_option(CODOC_TOKEN_OPTION_NAME);
			$CODOC_AUTHINFO = get_option(CODOC_AUTHINFO_OPTION_NAME);
			if( !$CODOC_SETTINGS ) {
				//デフォルト値
				$CODOC_SETTINGS = array(
					'css_path'	=> '',
				);
				update_option( CODOC_SETTINGS_OPTION_NAME, $CODOC_SETTINGS );
			}
			if (!isset($CODOC_SETTINGS['str_replace_binded_url_from'])) {
				$CODOC_SETTINGS['str_replace_binded_url_from'] = '';
			}
			if (!isset($CODOC_SETTINGS['str_replace_binded_url_to'])) {
				$CODOC_SETTINGS['str_replace_binded_url_to'] = '';
			}
			
			add_settings_section(
				'setting_section_id',    // id
				'codoc 設定ページ',      // title
				function (){},           // callback
				'codoc'                  // page
			);
			// 認証がある場合
			if ($CODOC_AUTHINFO) {
				register_setting(
					'codoc_option_group',	   // option group
					CODOC_SETTINGS_OPTION_NAME // option name(DB)
				);
				add_settings_field(
					'css_path',				   // id
					'カスタマイズ用CSSパス',  // title
					function() {
						global $CODOC_SETTINGS;
						echo sprintf('<input type="text" name="%s[css_path]" value="%s">',CODOC_SETTINGS_OPTION_NAME,$CODOC_SETTINGS['css_path']);
					},
					'codoc',				   //page
					'setting_section_id'	   //Section
				);
				add_settings_field(
					'str_replace_binded_url',				   // id
					'codoc側に登録するパーマリンクを置換',  // title
					function() {
						global $CODOC_SETTINGS;
						echo sprintf('<input type="text" name="%s[str_replace_binded_url_from]" value="%s">',CODOC_SETTINGS_OPTION_NAME,$CODOC_SETTINGS['str_replace_binded_url_from']);
						echo ('を');
						echo sprintf('<input type="text" name="%s[str_replace_binded_url_to]" value="%s">',CODOC_SETTINGS_OPTION_NAME,$CODOC_SETTINGS['str_replace_binded_url_to']);
						echo ('に変換');
					},
					'codoc',				   //page
					'setting_section_id'	   //Section
				);

				register_setting(
					'codoc_option_group',	   // option group
					CODOC_USERCODE_OPTION_NAME
				);
				register_setting(
					'codoc_option_group',	   // option group
					CODOC_TOKEN_OPTION_NAME
				);
				
				if (isset($_GET['codoc_auth_finished']) and $_GET['codoc_auth_finished']) {
					add_settings_error( 'general', 'settings_updated', __( 'codocの認証が完了しました' ), 'success' );
				}
				
				add_settings_field(
					'codoc_auth',
					'認証',
					function() {
						global $CODOC_USERCODE;
						global $CODOC_TOKEN;
						global $CODOC_AUTHINFO;
						$script = "javascript:document.getElementById('codoc-usercode').value='';document.getElementById('codoc-token').value=' ';document.getElementById('codoc-auth-message').innerText='解除を完了するには変更を保存してください';document.getElementById('codoc-auth-message').color='red';";

						echo sprintf('<p><font color="green" id="codoc-auth-message"><strong>%s</strong> で認証済</font></p>',$CODOC_AUTHINFO['email']);

						echo sprintf('<input id="codoc-usercode" type="hidden" name="%s" value="%s">',CODOC_USERCODE_OPTION_NAME,$CODOC_USERCODE);
						echo sprintf('<input id="codoc-token" type="hidden" name="%s" value="%s">',CODOC_TOKEN_OPTION_NAME,$CODOC_TOKEN);
						echo sprintf('<p>認証を<a href="javascript:void(0);" onClick="' . $script . '">解除する</p>');
					},
					'codoc',	
					'setting_section_id'
				);
				
			}

			// ない場合
			if (!$CODOC_AUTHINFO and !isset($_GET['auth_by_myself'])) {
				add_settings_field(
					'codoc_auth',
					'認証',
					function() {
						
						//$current_url  = (empty($_SERVER['HTTPS']) ? 'http://' : 'https://').$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
						$current_url  = admin_url('options-general.php') . '?page=codoc';
						$login_url    = sprintf("location.href='%s'",CODOC_URL . '/me/token?from=wp&return_url=' . urlencode($current_url));
						$register_url = sprintf("location.href='%s'",CODOC_URL . '/register?from=wp&return_url=' . urlencode($current_url));
						// submitを消しておく
						echo ('<script type="text/javascript">window.onload=function(){document.getElementById(\'submit\').style.display = \'none\'}</script>');
						echo ('codocをWordPressでご利用いただくには認証が必要です。<br />');
						echo sprintf('ユーザーコードとAPIトークンを<a href="%s&auth_by_myself=1">直接入力</a>することでも認証できます。<br /><br />',$current_url);
						echo sprintf('<input type="button" class="button button-primary" value="ログインして認証" onClick="%s">　<input type="button" class="button button-primary" value="登録して認証" onClick="%s"><br /><br />',$login_url,$register_url);
						

					},
					'codoc',	
					'setting_section_id'
				);
			}
			// ない場合かつ自分で認証する場合
			if (!$CODOC_AUTHINFO and (isset($_GET['auth_by_myself']) and $_GET['auth_by_myself'])) {
				register_setting(
					'codoc_option_group',	   // option group
					CODOC_USERCODE_OPTION_NAME
				);
				add_settings_field(
					'codoc_usercode',
					'ユーザーコード',
					function() {
						global $CODOC_USERCODE;
						echo sprintf('<input type="text" name="%s" value="%s">',CODOC_USERCODE_OPTION_NAME,$CODOC_USERCODE);
					},
					'codoc',	
					'setting_section_id'
				);
				register_setting(
					'codoc_option_group',	   // option group
					CODOC_TOKEN_OPTION_NAME
				);
				add_settings_field(
					'codoc_token',
					'APIトークン',
					function() {
						global $CODOC_TOKEN;
						echo sprintf('<input type="text" name="%s" value="%s">',CODOC_TOKEN_OPTION_NAME,$CODOC_TOKEN);
					},
					'codoc',	
					'setting_section_id'
				);
			}
			
			//　認証情報を保存			
			add_action( 'update_option_' . CODOC_USERCODE_OPTION_NAME, function( $old_value, $new_value ) {
				global $CODOC_RE_AUTHORIZE;
				$CODOC_RE_AUTHORIZE = 1;
			},9,2); // $hook, $function_to_add, $priority, $accepted_args
			add_action( 'update_option_' . CODOC_TOKEN_OPTION_NAME, function( $old_value, $new_value ) {
				global $CODOC_RE_AUTHORIZE;
				$CODOC_RE_AUTHORIZE = 1;
			},10,2);
			add_action('updated_option',function(){
				global $CODOC_RE_AUTHORIZE;
				if ($CODOC_RE_AUTHORIZE) {
					$data = $this->callAPI('GET','');
					if ($data->status and $user = $data->user) {
						update_option(CODOC_AUTHINFO_OPTION_NAME,[
							'email' => $user->email,
							'name'  => $user->name,
						]);
					} else {
						update_option(CODOC_AUTHINFO_OPTION_NAME,'');
					}
				}
			});
			
		});
		// プラグイン一覧に設定のリンクをいれる
		add_filter( 'plugin_action_links_' . plugin_basename( plugin_dir_path( __FILE__ ) . 'codoc' . '.php' ),
					function( $links ) {
						$setting_link = sprintf( '<a href="%s">%s</a>', esc_url( add_query_arg( 'page', 'codoc', admin_url( 'options-general.php' ) ) ), esc_html( '設定' ) );
						array_unshift( $links, $setting_link );
						
						return $links;
					}
		);
		
	}
	public function add_mce() {
		// Add Shortcode options in the WordPres visual editors
        //wp_enqueue_script( 'codoc-editor-script', CODOC_URL . 'codoc/src_mce/codoc-editor.js');
        
		add_action( 'init', function() {
			if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) ) {
				return;
			}
			if ( get_user_option( 'rich_editing' ) == 'true' ) {
				// プラグイン内で使うCSRF を生成
				$path = plugins_url( 'codoc/src_mce/codoc-editor-onload.js', __DIR__ );
				wp_enqueue_script(	'codoc-editor-onload', $path, array('jquery'), '', true );
				// I just want to insert this global variables but i don't know how i can do it..
				wp_localize_script(
					'codoc-editor-onload',
					'CODOCEDITOR', 
					array(
						'action' => 'codoc_shortcodes',
						'nonce'  => wp_create_nonce( 'codoc_shortcodes' ),
                        
                        'codoc_url'      => CODOC_URL,
                        'codoc_usercode' => get_option(CODOC_USERCODE_OPTION_NAME),
                        'codoc_plugin_version' => CODOC_PLUGIN_VERSION,
                        'codoc_sdk_path'       => CODOC_SDK_PATH,
					)
				);

				// ここでtinymceのプラグイン追加
				//wp_enqueue_style( 'codoc-admin-style', plugins_url( 'codoc/src_mce/codoc-admin.css', __DIR__ ) );
				//add_editor_style( plugins_url( 'codoc/src_mce/codoc-admin.css', __DIR__ ) );
                wp_enqueue_style( 'codoc-admin-style', CODOC_URL . CODOC_SDK_PATH . '.tinymce.css?c=' . date('Ymd') );
                add_editor_style( CODOC_URL .  CODOC_SDK_PATH . '.tinymce.css' );

				add_filter( 'mce_external_plugins', function( $plugin_array ) {
					//$plugin_array['codoc'] = plugins_url( 'codoc/src_mce/codoc-editor.js', __DIR__ );
                    $plugin_array['codoc'] = CODOC_URL .  CODOC_SDK_PATH . '.tinymce.js?c=' . date('Ymd');
					return $plugin_array;
				} );
				add_filter( 'mce_buttons', function( $buttons ) {
					array_push( $buttons, "|", "codoc" );
					return $buttons;
				} );

			}
		} );
	}
	public function save_post($post_ID,$post,$update) {
		if (preg_match('/^(auto-draft|inherit)$/',$post->post_status)) {
			return;
		}
		
		$post_content = $post->post_content;
		preg_match('/wp:codoc\/codoc-block +?({.*})/',$post_content,$matches);
		// GUTENBERG で指定されたjson(記事情報)がない場合
		if (!$matches) {
			return;
		}
		// GUTENBERG で保存している内容を取得
		$codoc_info = json_decode($matches[1],true);
		// codoc タグがない場合はなにもしない
		//preg_match('/(<span +data-id="codoc-tag"[^>]+>(?:.+|)<\/span>)/',$post_content,$matches);
		preg_match('/(<(?:span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:span|div)>)/',$post_content,$matches);		
		if (!$matches) {
			return;
		}
		// TODO: split or html parse? HTMLがつながってる場合はおかしくなる
        // classic(tinymce)版の場合p、もしくはdivにかこまれている
		$splited  = preg_split('/(?:<(?:div|p)(?:[^>]+|)>|)<\!-- +wp:codoc\/codoc-block .*<\!-- +\/wp:codoc\/codoc-block +-->(?:<\/(?:div|p)>|)/s',$post_content);
		$status = $post->post_status == 'publish' ? 1 : 0;
		# $body_free = '';
		# $body_paywalled = '';
		# if (count($splited) >= 2) {
		# 	
		# }
		$binded_url = get_permalink($post_ID);
		$CODOC_SETTINGS = get_option(CODOC_SETTINGS_OPTION_NAME);
		if (isset($CODOC_SETTINGS['str_replace_binded_url_from']) and
			isset($CODOC_SETTINGS['str_replace_binded_url_to']) and
			$CODOC_SETTINGS['str_replace_binded_url_from']) {
			$binded_url = str_replace(sanitize_text_field($CODOC_SETTINGS['str_replace_binded_url_from']),
									  sanitize_text_field($CODOC_SETTINGS['str_replace_binded_url_to']),
									  $binded_url);
		}
		
		$params = [
			'title'          => $post->post_title,
			'body_free'      => $splited[0],
			'body_paywalled' => $splited[1],
			'status'         => $status,
			'binded_url'     => $binded_url,
			'show_price'     => isset($codoc_info['showPrice']) ? ($codoc_info['showPrice'] ? 1 : 0) : 0,
			'price'          => isset($codoc_info['price']) ? $codoc_info['price'] : 100,
			'limited'        => isset($codoc_info['limited']) ? ($codoc_info['limited'] ? 1 : 0) : 0,
			'limited_count'  => isset($codoc_info['limitedCount']) ? $codoc_info['limitedCount'] : 1,
			'affiliate_mode' => isset($codoc_info['affiliateMode']) ? ($codoc_info['affiliateMode'] ? 1 : 0) : 0,
			'affiliate_rate' => isset($codoc_info['affiliateRate']) ? $codoc_info['affiliateRate'] : '0.0500',
			'show_support'   => isset($codoc_info['showSupport']) ? ($codoc_info['showSupport'] ? 1 : 0) : 0,
			'subscriptions'  => isset($codoc_info['subscriptions']) ? array_keys($codoc_info['subscriptions']) : [],
		];
		$entryCode = get_post_meta($post_ID,'codoc_entry_code',true);
		if ($entryCode) {
			$res = $this->callAPI('PUT','/entries/' . $entryCode ,$params);
		} else {
			$res = $this->callAPI('POST', '/entries', $params);
			if (is_object($res) and $res->status) {
				update_post_meta($post_ID,'codoc_entry_code',$res->entry->code);
			}
		}
		return true;
	}
	function updated_post_meta( $meta_ID, $post_ID, $meta_key ) {
		if ($meta_key != '_thumbnail_id') {
			return;
		}
		if ( has_post_thumbnail($post_ID) ) {
			$attachment = wp_get_attachment_metadata( get_post_thumbnail_id($post_ID));
			$upload_dir = wp_upload_dir();
			$file_path  = sprintf ('%s/%s',$upload_dir['basedir'],$attachment['file']);
			
			if (is_readable($file_path)) {
				$name = 'file';

				$boundary = wp_generate_password(24);

				$payload = '';
				$payload .= '--' . $boundary;
				$payload .= "\r\n";
				$payload .= 'Content-Disposition: form-data; name="' . $name . '"; filename="' . basename( $file_path ) . '"' . "\r\n";
				$payload .= "Content-Type: application/octet-stream\r\n";
				$payload .= "Content-Transfer-Encoding: binary\r\n";
				$payload .= "\r\n";
				$payload .= file_get_contents( $file_path );
				$payload .= "\r\n";
				
				$payload .= '--' . $boundary . '--';
				
				
				$entryCode = get_post_meta($post_ID,'codoc_entry_code',true);
				$res = $this->callAPI(
					'POST',
					'/entries/' . $entryCode . '/thumbnail',
					$payload,
					['content-type' => 'multipart/form-data; boundary=' . $boundary]
				);
			}
		}
	} 
	function deleted_post_meta( $meta_ids, $post_ID, $meta_key,$meta_value ) {
		if ($meta_key != '_thumbnail_id') {
			return;
		}
		$entryCode = get_post_meta($post_ID,'codoc_entry_code',true);
		$res = $this->callAPI(
			'POST',
			'/entries/' . $entryCode . '/thumbnail',
			[ "reset" => 1 ]
		);
	} 
	function the_content( $post_content ) {
		if ( is_single() && in_the_loop() && is_main_query() ) {
		}
		// codoc タグがあるかどうか (202001:span -> div に変更)
		preg_match('/(<(span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:div|span)>)/',$post_content,$matches);
		// data-wp-plugin-ver が無いタグは分割しない
		if (!$matches) {
			return $post_content;
		}
        // codocタグで分割 (202001: gutenbergで直前のdivタグを削除)
		$tag_regex = '/(?:<div(?:[^>]+|)>|)<(?:span|div)[^>]+data-id="codoc-tag"(?:[^>]+|)>(?:.+|)<\/(?:span|div)>(?:<\/div>|)/';
		if ( is_preview() ) {
            $post_content = preg_replace($tag_regex,'<div class="codoc-continue">ここから上は無料で表示されます</div>',$post_content);
			return $post_content;
		}
		// codoc タグの前後で分ける
		$splited  = preg_split($tag_regex,$post_content);
		// codoc タグにID属性のentrycodeとdata-without-body(無料分を非表示)をつける
		$post = get_post();
		$entryCode = sprintf('"codoc-entry-%s" ',get_post_meta($post->ID,'codoc_entry_code',true));
        $codoc_tag = preg_replace('/<((?:span|div)[^>]+)data-id="[^"]+"((?:[^>]+|))>/','<${1} ${2} data-without-body="1" id=' . $entryCode  . ">", $matches[1]);
        # サポートからの問い合わせで div class が divclass になることがある
        $codoc_tag = preg_replace('/divclass/','div class',$codoc_tag);
		// 無料部分のみ表示
		return $splited[0] . sprintf('<div class="wp-block-codoc-codoc-block">%s</div>',$codoc_tag);
	}

	
}


```
