PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/jetpack/modules/publicize.php

https://gitlab.com/hunt9310/ras
PHP | 307 lines | 194 code | 55 blank | 58 comment | 39 complexity | 7787b59c7e3ba94cd8101bcbe770b66c MD5 | raw file
  1. <?php
  2. /**
  3. * Module Name: Publicize
  4. * Module Description: Automated social marketing.
  5. * Sort Order: 10
  6. * Recommendation Order: 7
  7. * First Introduced: 2.0
  8. * Requires Connection: Yes
  9. * Auto Activate: Yes
  10. * Module Tags: Social, Recommended
  11. * Feature: Engagement
  12. * Additional Search Queries: facebook, twitter, google+, googleplus, google, path, tumblr, linkedin, social, tweet, connections, sharing
  13. */
  14. class Jetpack_Publicize {
  15. public $in_jetpack = true;
  16. function __construct() {
  17. global $publicize_ui;
  18. $this->in_jetpack = ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'enable_module_configurable' ) ) ? true : false;
  19. if ( $this->in_jetpack && method_exists( 'Jetpack', 'module_configuration_load' ) ) {
  20. Jetpack::enable_module_configurable( __FILE__ );
  21. Jetpack::module_configuration_load( __FILE__, array( $this, 'jetpack_configuration_load' ) );
  22. }
  23. require_once dirname( __FILE__ ) . '/publicize/publicize.php';
  24. if ( $this->in_jetpack )
  25. require_once dirname( __FILE__ ) . '/publicize/publicize-jetpack.php';
  26. else {
  27. require_once dirname( dirname( __FILE__ ) ) . '/mu-plugins/keyring/keyring.php';
  28. require_once dirname( __FILE__ ) . '/publicize/publicize-wpcom.php';
  29. }
  30. require_once dirname( __FILE__ ) . '/publicize/ui.php';
  31. $publicize_ui = new Publicize_UI();
  32. $publicize_ui->in_jetpack = $this->in_jetpack;
  33. // Jetpack specific checks / hooks
  34. if ( $this->in_jetpack) {
  35. // if sharedaddy isn't active, the sharing menu hasn't been added yet
  36. $active = Jetpack::get_active_modules();
  37. if ( in_array( 'publicize', $active ) && !in_array( 'sharedaddy', $active ) )
  38. add_action( 'admin_menu', array( &$publicize_ui, 'sharing_menu' ) );
  39. }
  40. }
  41. function jetpack_configuration_load() {
  42. wp_safe_redirect( menu_page_url( 'sharing', false ) );
  43. exit;
  44. }
  45. }
  46. global $publicize_ui;
  47. new Jetpack_Publicize;
  48. /**
  49. * Helper functions for shared use in the services files
  50. */
  51. class Publicize_Util {
  52. /**
  53. * Truncates a string to be shorter than or equal to the length specified
  54. * Attempts to truncate on word boundaries
  55. *
  56. * @param string $string
  57. * @param int $length
  58. * @return string
  59. */
  60. public static function crop_str( $string, $length = 256 ) {
  61. $string = Publicize_Util::sanitize_message( $string );
  62. $length = absint( $length );
  63. if ( mb_strlen( $string, 'UTF-8' ) <= $length ) {
  64. return $string;
  65. }
  66. // @see wp_trim_words()
  67. if ( 'characters' == _x( 'words', 'word count: words or characters?', 'jetpack' ) ) {
  68. return trim( mb_substr( $string, 0, $length - 1, 'UTF-8' ) ) . "\xE2\x80\xA6"; // ellipsis
  69. }
  70. $words = explode( ' ', $string );
  71. $return = '';
  72. while ( strlen( $word = array_shift( $words ) ) ) {
  73. $new_return = $return ? "$return $word" : $word;
  74. $new_return_length = mb_strlen( $new_return, 'UTF-8' );
  75. if ( $new_return_length < $length - 1 ) {
  76. $return = $new_return;
  77. continue;
  78. } elseif ( $new_return_length == $length - 1 ) {
  79. $return = $new_return;
  80. break;
  81. }
  82. if ( !$return ) {
  83. $return = mb_substr( $new_return, 0, $length - 1, 'UTF-8' );
  84. }
  85. break;
  86. }
  87. return "$return\xE2\x80\xA6"; // ellipsis
  88. }
  89. /**
  90. * Returns an array of DOMNodes that are comments (including recursing child nodes)
  91. *
  92. * @param DOMNode $node
  93. * @return array
  94. */
  95. function get_comment_nodes( $node ) {
  96. $comment_nodes = array();
  97. foreach ( $node->childNodes as $child ) {
  98. if ( XML_COMMENT_NODE === $child->nodeType ) {
  99. $comment_nodes[] = $child;
  100. }
  101. if ( $child->hasChildNodes() ) {
  102. $child_comment_nodes = self::get_comment_nodes( $child );
  103. $comment_nodes = array_merge( $comment_nodes, $child_comment_nodes );
  104. }
  105. }
  106. return $comment_nodes;
  107. }
  108. /**
  109. * Truncates HTML so that its textContent (text without markup) is shorter than or equal to the length specified.
  110. * The length of the returned string may be larger than the specified length due to the markup.
  111. * Attempts to truncate on word boundaries.
  112. *
  113. * @param string $string
  114. * @param int $length
  115. * @param array $allowed_tags KSES input
  116. * @return string
  117. */
  118. function crop_html( $string, $length = 256, $allowed_tags = array() ) {
  119. $tags = $GLOBALS['allowedtags']; // Markup allowed in comments...
  120. $tags['img'] = array( // ... plus images ...
  121. 'alt' => true,
  122. 'height' => true,
  123. 'src' => true,
  124. 'width' => true,
  125. );
  126. // ... and some other basics
  127. $tags['p'] = array();
  128. $tags['ul'] = array();
  129. $tags['ol'] = array();
  130. $tags['li'] = array();
  131. $tags['br'] = array();
  132. $tags = array_merge( $tags, $allowed_tags );
  133. // Clean up, then KSES to really lock it down
  134. $string = trim( (string) $string );
  135. $string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
  136. $string = wp_kses( $string, $tags );
  137. $string = mb_convert_encoding( $string, 'HTML-ENTITIES', 'UTF-8' );
  138. $dom = new DOMDocument( '1.0', 'UTF-8' );
  139. @$dom->loadHTML( "<html><body>$string</body></html>" ); // suppress parser warning
  140. // Strip comment nodes, if any
  141. $comment_nodes = self::get_comment_nodes( $dom->documentElement );
  142. foreach ( $comment_nodes as &$comment_node ) {
  143. $comment_node->parentNode->removeChild( $comment_node );
  144. }
  145. if ( $comment_nodes ) {
  146. // Update the $string (some return paths work from just $string)
  147. $string = $dom->saveHTML();
  148. $string = preg_replace( '/^<!DOCTYPE.+?>/', '', $string );
  149. $string = str_replace( array('<html>', '</html>', '<body>', '</body>' ), array( '', '', '', '' ), $string );
  150. $string = trim( $string );
  151. }
  152. // Find the body
  153. $body = false;
  154. foreach ( $dom->childNodes as $child ) {
  155. if ( XML_ELEMENT_NODE === $child->nodeType && 'html' === strtolower( $child->tagName ) ) {
  156. $body = $child->firstChild;
  157. break;
  158. }
  159. }
  160. if ( !$body ) {
  161. return self::crop_str( $string, $length );
  162. }
  163. // If the text (without the markup) is shorter than $length, just return
  164. if ( mb_strlen( $body->textContent, 'UTF-8' ) <= $length ) {
  165. return $string;
  166. }
  167. $node = false;
  168. do {
  169. $node = self::remove_innermost_last_child( $body, $node_removed_from );
  170. $new_string_length = mb_strlen( $body->textContent, 'UTF-8' );
  171. } while ( $new_string_length > $length );
  172. $new_string = $dom->saveHTML( $body );
  173. $new_string = mb_substr( $new_string, 6, -7, 'UTF-8' ); // 6: <body>, 7: </body>
  174. if ( !$node ) {
  175. return $new_string ? $new_string : self::crop_str( $string, $length );
  176. }
  177. $append_string_length = $length - $new_string_length;
  178. if ( !$append_string_length ) {
  179. return $new_string;
  180. }
  181. if ( $append_string_length > 1 && XML_TEXT_NODE === $node->nodeType ) { // 1: ellipsis
  182. $append_string = self::crop_str( $node->textContent, $append_string_length ); // includes ellipsis
  183. $append_node = $dom->createTextNode( $append_string );
  184. $node_removed_from->appendChild( $append_node );
  185. $new_string = $dom->saveHTML( $body );
  186. $new_string = mb_substr( $new_string, 6, -7, 'UTF-8' );
  187. } elseif ( $append_string_length > 9 && XML_ELEMENT_NODE === $node->nodeType && 'p' == strtolower( $node->nodeName ) ) { // 9: '<p>X{\xE2\x80\xA6}</p>'
  188. $new_string .= '<p>' . self::crop_str( $node->textContent, $append_string_length - 8 ) . '</p>';
  189. }
  190. // Clean up any empty Paragraphs that might have occurred after removing their children
  191. return trim( preg_replace( '#<p>\s*</p>#i', '', $new_string ) );
  192. }
  193. function remove_innermost_last_child( $node, &$node_removed_from ) {
  194. $node_removed_from = $node;
  195. if ( !$node->lastChild ) {
  196. return false;
  197. }
  198. if ( $node->lastChild->hasChildNodes() ) {
  199. return self::remove_innermost_last_child( $node->lastChild, $node_removed_from );
  200. }
  201. $innermost_last_child = $node->lastChild;
  202. $node->removeChild( $innermost_last_child );
  203. return $innermost_last_child;
  204. }
  205. function bump_stats_extras_publicize_url( $bin, $post_id ) {
  206. static $done = array();
  207. if ( isset( $done[$post_id] ) ) {
  208. return;
  209. }
  210. $done[$post_id] = true;
  211. /** This action is documented in modules/widgets/social-media-icons.php */
  212. do_action( 'jetpack_bump_stats_extras', 'publicize_url', $bin );
  213. }
  214. public static function build_sprintf( $args ) {
  215. $search = array();
  216. $replace = array();
  217. foreach ( $args as $k => $arg ) {
  218. if ( 0 == $k ) {
  219. $string = $arg;
  220. continue;
  221. }
  222. $search[] = "%$arg%";
  223. $replace[] = "%$k\$s";
  224. }
  225. return str_replace( $search, $replace, $string );
  226. }
  227. public static function sanitize_message( $message ) {
  228. $message = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $message );
  229. $message = wp_kses( $message, array() );
  230. $message = preg_replace('/[\r\n\t ]+/', ' ', $message);
  231. $message = trim( $message );
  232. $message = htmlspecialchars_decode( $message, ENT_QUOTES );
  233. return $message;
  234. }
  235. }
  236. if( ! ( defined( 'IS_WPCOM' ) && IS_WPCOM ) && ! function_exists( 'publicize_init' ) ) {
  237. /**
  238. * Helper for grabbing a Publicize object from the "front-end" (non-admin) of
  239. * a site. Normally Publicize is only loaded in wp-admin, so there's a little
  240. * set up that you might need to do if you want to use it on the front end.
  241. * Just call this function and it returns a Publicize object.
  242. *
  243. * @return Publicize Object
  244. */
  245. function publicize_init() {
  246. global $publicize;
  247. if ( ! class_exists( 'Publicize' ) ) {
  248. require_once dirname( __FILE__ ) . '/publicize/publicize.php';
  249. }
  250. return $publicize;
  251. }
  252. }