Adding Textile and Markdown Extra options to a PunBB 1.2.17 forum ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ by Stef Dawson (http://stefdawson.com/) =================== New database fields =================== ALTER TABLE `pbb_users` ADD `markup_system` VARCHAR( 15 ) NOT NULL DEFAULT 'BBCode'; INSERT INTO `pbb_config` ( `conf_name` , `conf_value` ) VALUES ( 'p_message_textile', '0' ), ( 'p_message_markdown', '0' ); INSERT INTO `pbb_config` ( `conf_name` , `conf_value` ) VALUES ( 'p_sig_textile', '0' ), ( 'p_sig_markdown', '0' ); (you may optionally alter install.php to include the new fields too) ======================= lang/English/common.php ======================= Replace: 'img tag' => '[img] tag', With: 'Textile' => 'Textile', // nor this 'Markdown' => 'Markdown Extra', // nor this 'img tag' => 'image markup', ======================== lang/English/profile.php ======================== Find: 'Style info' => 'If you like you can use a different visual style for this forum.', And add afterwards: 'Markup legend' => 'Select your preferred markup system', 'Markup info' => 'If you like you can use one of these systems to add markup to your posts.', ===================== admin_permissions.php ===================== Replace: Image tag /> Yes    /> No Allow the BBCode [img][/img] tag in posts. With: Textile /> Yes    /> No Allow Textile in posts (optional). Markdown /> Yes    /> No Allow Markdown in posts (optional). Image tag /> Yes    /> No Allow images in posts. Replace: Image tag in signatures /> Yes    /> No Allow the BBCode [img][/img] tag in user signatures (not recommended). With: Textile in signatures /> Yes    /> No Allow Textile in user signatures. Markdown in signatures /> Yes    /> No Allow Markdown in user signatures. Image tag in signatures /> Yes    /> No Allow images in user signatures (not recommended). =========== profile.php =========== Replace: // Validate BBCode syntax if ($pun_config['p_sig_bbcode'] == '1' && strpos($form['signature'], '[') !== false && strpos($form['signature'], ']') !== false) { require PUN_ROOT.'include/parser.php'; $form['signature'] = preparse_bbcode($form['signature'], $foo, true); } With: // Validate BBCode syntax if ($pun_config['p_sig_bbcode'] == '1' || $pun_config['p_sig_textile'] == '1' || $pun_config['p_sig_markdown'] == '1') { require PUN_ROOT.'include/parser.php'; } if ($pun_config['p_sig_bbcode'] == '1' && strpos($form['signature'], '[') !== false && strpos($form['signature'], ']') !== false) { $form['signature'] = preparse_bbcode($form['signature'], $foo, true); } A few lines later, replace: $form = extract_elements(array('disp_topics', 'disp_posts', 'show_smilies', 'show_img', 'show_img_sig', 'show_avatars', 'show_sig', 'style')); With: $form = extract_elements(array('disp_topics', 'disp_posts', 'show_smilies', 'show_img', 'show_img_sig', 'show_avatars', 'show_sig', 'style', 'markup_system')); About halfway down, find: $result = $db->query('SELECT u.username, u.email, u.title, u.realname, u.url, u.jabber, u.icq, u.msn, u.aim, u.yahoo, u.location, u.use_avatar, u.signature, u.disp_topics, u.disp_posts, u.email_setting, u.save_pass, u.notify_with_post, u.show_smilies, u.show_img, u.show_img_sig, u.show_avatars, u.show_sig, u.timezone, u.language, u.style, u.num_posts, u.last_post, u.registered, u.registration_ip, u.admin_note, g.g_id, g.g_user_title FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id='.$id) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error()); And replace with: $result = $db->query('SELECT u.username, u.email, u.title, u.realname, u.url, u.jabber, u.icq, u.msn, u.aim, u.yahoo, u.location, u.use_avatar, u.signature, u.disp_topics, u.disp_posts, u.email_setting, u.save_pass, u.notify_with_post, u.show_smilies, u.show_img, u.show_img_sig, u.show_avatars, u.show_sig, u.timezone, u.language, u.style, u.markup_system, u.num_posts, u.last_post, u.registered, u.registration_ip, u.admin_note, g.g_id, g.g_user_title FROM '.$db->prefix.'users AS u LEFT JOIN '.$db->prefix.'groups AS g ON g.g_id=u.group_id WHERE u.id='.$id) or error('Unable to fetch user info', __FILE__, __LINE__, $db->error()); Near the bottom, find:
  • :
  • Replace with:
  • :
  • :
  • :
  • A bit further on, find the post display legend:
    And immediately before it, insert this code:
    '."\n"; else if (count($markup) > 1) { natsort($markup); ?>
    =================== edit.php & post.php =================== Replace: // Validate BBCode syntax if ($pun_config['p_message_bbcode'] == '1' && strpos($message, '[') !== false && strpos($message, ']') !== false) { require PUN_ROOT.'include/parser.php'; $message = preparse_bbcode($message, $errors); } With: // Validate BBCode syntax if ($pun_config['p_message_bbcode'] == '1' || $pun_config['p_message_textile'] == '1' || $pun_config['p_message_markdown'] == '1') { require PUN_ROOT.'include/parser.php'; } if ($pun_config['p_message_bbcode'] == '1' && strpos($message, '[') !== false && strpos($message, ']') !== false) { $message = preparse_bbcode($message, $errors); } And replace:
  • :
  • With:
  • :
  • :
  • :
  • Additionally, in post.php, find (about 2/3 of the way down): if ($pun_config['p_message_bbcode'] == '1') Replace with: if ($pun_config['p_message_textile'] == '1' && $pun_user['markup_system'] == $lang_common['Textile']) { $quote = '*'.$q_poster.' '.$lang_common['wrote'].':*'."\n\n".'bq. '.$q_message."\n"; } else if ($pun_config['p_message_markdown'] == '1' && $pun_user['markup_system'] == $lang_common['Markdown']) { $quote = '**'.$q_poster.' '.$lang_common['wrote'].':**'."\n\n".'> '.$q_message."\n"; } else if ($pun_config['p_message_bbcode'] == '1' && $pun_user['markup_system'] == $lang_common['BBCode']) ============= viewtopic.php ============= Again, replace:
  • :
  • With:
  • :
  • :
  • :
  • ================== include/common.php ================== After the commonly used defines block (about line 89ish), Add: if (!defined('PUN_PATH_TEXTILE')) define('PUN_PATH_TEXTILE', PUN_ROOT.'../textpattern/lib/'); if (!defined('PUN_PATH_MARKDOWN')) define('PUN_PATH_MARKDOWN', PUN_ROOT.'include/'); (obviously change these locations for your install!) ================== include/parser.php ================== Replace function handle_img_tag() with: function handle_img_tag($url, $is_signature = false, $linkurl = false, $alttext = false) { global $lang_common, $pun_config, $pun_user; $alttext = ($alttext) ? $alttext : $url; $img_tag = '<'.$lang_common['Image link'].'>'; if ($is_signature && $pun_config['p_sig_img_tag'] == '1' && $pun_user['show_img_sig'] != '0') $img_tag = ''.htmlspecialchars($alttext).''; else if (!$is_signature && $pun_config['p_message_img_tag'] == '1' && $pun_user['show_img'] != '0') $img_tag = ''.htmlspecialchars($alttext).''; if ($linkurl && substr($img_tag, 0, 4) == "'.$img_tag.''; return $img_tag; } Replace function parse_message() with: // // Parse message text // function parse_message($text, $hide_smilies) { global $pun_config, $lang_common, $pun_user; if ($pun_config['o_censoring'] == '1') $text = censor_words($text); if ($pun_config['p_message_textile'] == '1' && $pun_user['markup_system'] == $lang_common['Textile']) { include_once PUN_PATH_TEXTILE.'classTextile.php'; // Replace (optionally anchored) images with links if necessary $text = preg_replace('#\!((ht|f)tps?://)([^\s<"]*?)\!\:((ht|f)tps?://)([^\s<"]*)#e', 'handle_img_tag(\'$1$3\', false, \'$4$6\')', $text); $text = preg_replace('#\!((ht|f)tps?://)([^\s<"]*?)\!#e', 'handle_img_tag(\'$1$3\')', $text); // Process textile - leave images on to preserve smilies and links to images from handle_img_tag() $textile = new Textile(); $text = $textile->TextileThis($text); // Replace smilies if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0') $text = do_smilies($text); } else if ($pun_config['p_message_markdown'] == '1' && $pun_user['markup_system'] == $lang_common['Markdown']) { include_once PUN_PATH_MARKDOWN.'markdown.php'; // Replace any HTML tags so they are safe $text = preg_replace("/(<\/?\w+[^>]*>)/e", "stripslashes(pun_htmlspecialchars('\\1'))", $text); if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0') $text = do_smilies($text); // Replace referenced, then standard images $text = preg_replace('#\!\[(.+)\]\s?\[(.+)\].*?\[\2\]\:\s?((ht|f)tps?://)([^\s<"]*)#es', 'handle_img_tag(\'$3$5\', true, false)', $text); $text = preg_replace('#\!\[(.+)\]\(((ht|f)tps?://)([^\)<]*?)\)#e', 'handle_img_tag(\'$2$4\', true, false, \'$1\')', $text); // Process markdown $text = Markdown($text); } else { // Assume BBCode // Convert applicable characters to HTML entities $text = pun_htmlspecialchars($text); // If the message contains a code tag we have to split it up (text within [code][/code] shouldn't be touched) if (strpos($text, '[code]') !== false && strpos($text, '[/code]') !== false) { list($inside, $outside) = split_text($text, '[code]', '[/code]'); $outside = array_map('ltrim', $outside); $text = implode('<">', $outside); } if ($pun_config['o_make_links'] == '1') $text = do_clickable($text); if ($pun_config['o_smilies'] == '1' && $pun_user['show_smilies'] == '1' && $hide_smilies == '0') $text = do_smilies($text); if ($pun_config['p_message_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false) { $text = do_bbcode($text); if ($pun_config['p_message_img_tag'] == '1') { // $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\')', $text); $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\')', $text); } } // Deal with newlines, tabs and multiple spaces $pattern = array("\n", "\t", ' ', ' '); $replace = array('
    ', '    ', '  ', '  '); $text = str_replace($pattern, $replace, $text); // If we split up the message before we have to concatenate it together again (code tags) if (isset($inside)) { $outside = explode('<">', $text); $text = ''; $num_tokens = count($outside); for ($i = 0; $i < $num_tokens; ++$i) { $text .= $outside[$i]; if (isset($inside[$i])) { $num_lines = ((substr_count($inside[$i], "\n")) + 3) * 1.5; $height_str = ($num_lines > 35) ? '35em' : $num_lines.'em'; $text .= '

    '.$lang_common['Code'].':

    '.$inside[$i].'

    '; } } } // Add paragraph tag around post, but make sure there are no empty paragraphs $text = str_replace('

    ', '', '

    '.$text.'

    '); } return $text; } Replace function parse_signature() with: // // Parse signature text // function parse_signature($text) { global $pun_config, $lang_common, $pun_user; if ($pun_config['o_censoring'] == '1') $text = censor_words($text); if ($pun_config['p_sig_textile'] == '1' && $pun_user['markup_system'] == $lang_common['Textile']) { include_once PUN_PATH_TEXTILE.'classTextile.php'; // Replace (optionally anchored) images with links if necessary $text = preg_replace('#\!((ht|f)tps?://)([^\s<"]*?)\!\:((ht|f)tps?://)([^\s<"]*)#e', 'handle_img_tag(\'$1$3\', true, \'$4$6\')', $text); $text = preg_replace('#\!((ht|f)tps?://)([^\s<"]*?)\!#e', 'handle_img_tag(\'$1$3\', true)', $text); // Process textile - leave images on here to preserve smilies and links to images from handle_img_tag() $textile = new Textile(); $text = $textile->TextileThis($text); // Replace smilies if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] != '0') $text = do_smilies($text); } else if ($pun_config['p_sig_markdown'] == '1' && $pun_user['markup_system'] == $lang_common['Markdown']) { include_once PUN_PATH_MARKDOWN.'markdown.php'; // Replace any HTML tags so they are safe $text = preg_replace("/(<\/?\w+[^>]*>)/e", "stripslashes(pun_htmlspecialchars('\\1'))", $text); if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] != '0') $text = do_smilies($text); // Replace referenced, then standard images $text = preg_replace('#\!\[(.+)\]\s?\[(.+)\].*?\[\2\]\:\s?((ht|f)tps?://)([^\s<"]*)#es', 'handle_img_tag(\'$3$5\', true, false)', $text); $text = preg_replace('#\!\[(.+)\]\(((ht|f)tps?://)([^\)<]*?)\)#e', 'handle_img_tag(\'$2$4\', true, false, \'$1\')', $text); // Process markdown $text = Markdown($text); } else { // Assume BBCode $text = pun_htmlspecialchars($text); if ($pun_config['o_make_links'] == '1') $text = do_clickable($text); if ($pun_config['o_smilies_sig'] == '1' && $pun_user['show_smilies'] != '0') $text = do_smilies($text); if ($pun_config['p_sig_bbcode'] == '1' && strpos($text, '[') !== false && strpos($text, ']') !== false) { $text = do_bbcode($text); if ($pun_config['p_sig_img_tag'] == '1') { // $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\.(jpg|jpeg|png|gif)\[/img\]#e', 'handle_img_tag(\'$1$3.$4\', true)', $text); $text = preg_replace('#\[img\]((ht|f)tps?://)([^\s<"]*?)\[/img\]#e', 'handle_img_tag(\'$1$3\', true)', $text); } } // Deal with newlines, tabs and multiple spaces $pattern = array("\n", "\t", ' ', ' '); $replace = array('
    ', '    ', '  ', '  '); $text = str_replace($pattern, $replace, $text); } return $text; } ===================== Then install markdown.php (Markdown Extra in this case) and classTextile.php (if you're not pointing at the one in your TXP install) in the locations you specified in include/common.php. Job done! :-)