PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 2.4.7
Jetpack – WP Security, Backup, Speed, & Growth v2.4.7
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / publicize.php

publicize.php in Jetpack – WP Security, Backup, Speed, & Growth 2.4.7, at modules/publicize.php

286 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Module Name: Publicize
4 * Module Description: Connect your site to popular social networks and automatically share new posts with your friends.
5 * Sort Order: 1
6 * First Introduced: 2.0
7 * Requires Connection: Yes
8 * Auto Activate: Yes
9 */
10
11 class Jetpack_Publicize {
12
13 var $in_jetpack = true;
14
15 function __construct() {
16 global $publicize_ui;
17
18 $this->in_jetpack = ( class_exists( 'Jetpack' ) && method_exists( 'Jetpack', 'enable_module_configurable' ) ) ? true : false;
19
20 if ( $this->in_jetpack && method_exists( 'Jetpack', 'module_configuration_load' ) ) {
21 Jetpack::enable_module_configurable( __FILE__ );
22 Jetpack::module_configuration_load( __FILE__, array( $this, 'jetpack_configuration_load' ) );
23 Jetpack_Sync::sync_posts( __FILE__ );
24 }
25
26 require_once dirname( __FILE__ ) . '/publicize/publicize.php';
27
28 if ( $this->in_jetpack )
29 require_once dirname( __FILE__ ) . '/publicize/publicize-jetpack.php';
30 else {
31 require_once dirname( dirname( __FILE__ ) ) . '/mu-plugins/keyring/keyring.php';
32 require_once dirname( __FILE__ ) . '/publicize/publicize-wpcom.php';
33 }
34
35 require_once dirname( __FILE__ ) . '/publicize/ui.php';
36 $publicize_ui = new Publicize_UI();
37 $publicize_ui->in_jetpack = $this->in_jetpack;
38
39 // Jetpack specific checks / hooks
40 if ( $this->in_jetpack) {
41 add_action( 'jetpack_activate_module_publicize', array( $this, 'module_state_toggle' ) );
42 add_action( 'jetpack_deactivate_module_publicize', array( $this, 'module_state_toggle' ) );
43
44 // if sharedaddy isn't active, the sharing menu hasn't been added yet
45 $active = Jetpack::get_active_modules();
46 if ( in_array( 'publicize', $active ) && !in_array( 'sharedaddy', $active ) )
47 add_action( 'admin_menu', array( &$publicize_ui, 'sharing_menu' ) );
48 }
49 }
50
51 function module_state_toggle() {
52 // extra check that we are on the JP blog, just incase
53 if ( class_exists( 'Jetpack' ) && $this->in_jetpack ) {
54 $jetpack = Jetpack::init();
55 $jetpack->sync->register( 'noop' );
56 }
57 }
58
59 function jetpack_configuration_load() {
60 wp_safe_redirect( menu_page_url( 'sharing', false ) );
61 exit;
62 }
63 }
64
65 global $publicize_ui;
66 new Jetpack_Publicize;
67
68 /**
69 * Helper functions for shared use in the services files
70 */
71 class Publicize_Util {
72 /**
73 * Truncates a string to be shorter than or equal to the length specified
74 * Attempts to truncate on word boundaries
75 *
76 * @param string $string
77 * @param int $length
78 * @return string
79 */
80 function crop_str( $string, $length = 256 ) {
81 $string = wp_strip_all_tags( (string) $string, true ); // true: collapse Linear Whitespace into " "
82 $length = absint( $length );
83
84 if ( mb_strlen( $string, 'UTF-8' ) <= $length ) {
85 return $string;
86 }
87
88 // @see wp_trim_words()
89 if ( 'characters' == _x( 'words', 'word count: words or characters?', 'jetpack' ) ) {
90 return trim( mb_substr( $string, 0, $length - 1, 'UTF-8' ) ) . "\xE2\x80\xA6"; // ellipsis
91 }
92
93 $words = explode( ' ', $string );
94
95 $return = '';
96 while ( strlen( $word = array_shift( $words ) ) ) {
97 $new_return = $return ? "$return $word" : $word;
98 $new_return_length = mb_strlen( $new_return, 'UTF-8' );
99 if ( $new_return_length < $length - 1 ) {
100 $return = $new_return;
101 continue;
102 } elseif ( $new_return_length == $length - 1 ) {
103 $return = $new_return;
104 break;
105 }
106
107 if ( !$return ) {
108 $return = mb_substr( $new_return, 0, $length - 1, 'UTF-8' );
109 }
110
111 break;
112 }
113
114 return "$return\xE2\x80\xA6"; // ellipsis
115 }
116
117
118 /**
119 * Returns an array of DOMNodes that are comments (including recursing child nodes)
120 *
121 * @param DOMNode $node
122 * @return array
123 */
124
125 function get_comment_nodes( $node ) {
126 $comment_nodes = array();
127 foreach ( $node->childNodes as $child ) {
128
129 if ( XML_COMMENT_NODE === $child->nodeType ) {
130 $comment_nodes[] = $child;
131 }
132
133 if ( $child->hasChildNodes() ) {
134 $child_comment_nodes = self::get_comment_nodes( $child );
135 $comment_nodes = array_merge( $comment_nodes, $child_comment_nodes );
136 }
137 }
138
139 return $comment_nodes;
140 }
141
142 /**
143 * Truncates HTML so that its textContent (text without markup) is shorter than or equal to the length specified.
144 * The length of the returned string may be larger than the specified length due to the markup.
145 * Attempts to truncate on word boundaries.
146 *
147 * @param string $string
148 * @param int $length
149 * @param array $allowed_tags KSES input
150 * @return string
151 */
152 function crop_html( $string, $length = 256, $allowed_tags = array() ) {
153 $tags = $GLOBALS['allowedtags']; // Markup allowed in comments...
154
155 $tags['img'] = array( // ... plus images ...
156 'alt' => true,
157 'height' => true,
158 'src' => true,
159 'width' => true,
160 );
161
162 // ... and some other basics
163 $tags['p'] = array();
164 $tags['ul'] = array();
165 $tags['ol'] = array();
166 $tags['li'] = array();
167 $tags['br'] = array();
168
169 $tags = array_merge( $tags, $allowed_tags );
170
171 // Clean up, then KSES to really lock it down
172 $string = trim( (string) $string );
173 $string = preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $string );
174 $string = wp_kses( $string, $tags );
175
176 $string = mb_convert_encoding( $string, 'HTML-ENTITIES', 'UTF-8' );
177 $dom = new DOMDocument( '1.0', 'UTF-8' );
178 @$dom->loadHTML( "<html><body>$string</body></html>" ); // suppress parser warning
179
180 // Strip comment nodes, if any
181 $comment_nodes = self::get_comment_nodes( $dom->documentElement );
182 foreach ( $comment_nodes as &$comment_node ) {
183 $comment_node->parentNode->removeChild( $comment_node );
184 }
185 if ( $comment_nodes ) {
186 // Update the $string (some return paths work from just $string)
187 $string = $dom->saveHTML();
188 $string = preg_replace( '/^<!DOCTYPE.+?>/', '', $string );
189 $string = str_replace( array('<html>', '</html>', '<body>', '</body>' ), array( '', '', '', '' ), $string );
190 $string = trim( $string );
191 }
192
193 // Find the body
194 $body = false;
195 foreach ( $dom->childNodes as $child ) {
196 if ( XML_ELEMENT_NODE === $child->nodeType && 'html' === strtolower( $child->tagName ) ) {
197 $body = $child->firstChild;
198 break;
199 }
200 }
201
202 if ( !$body ) {
203 return self::crop_str( $string, $length );
204 }
205
206 // If the text (without the markup) is shorter than $length, just return
207 if ( mb_strlen( $body->textContent, 'UTF-8' ) <= $length ) {
208 return $string;
209 }
210
211 $node = false;
212 do {
213 $node = self::remove_innermost_last_child( $body, $node_removed_from );
214 $new_string_length = mb_strlen( $body->textContent, 'UTF-8' );
215 } while ( $new_string_length > $length );
216
217 $new_string = $dom->saveHTML( $body );
218 $new_string = mb_substr( $new_string, 6, -7, 'UTF-8' ); // 6: <body>, 7: </body>
219
220 if ( !$node ) {
221 return $new_string ? $new_string : self::crop_str( $string, $length );
222 }
223
224 $append_string_length = $length - $new_string_length;
225
226 if ( !$append_string_length ) {
227 return $new_string;
228 }
229
230 if ( $append_string_length > 1 && XML_TEXT_NODE === $node->nodeType ) { // 1: ellipsis
231 $append_string = self::crop_str( $node->textContent, $append_string_length ); // includes ellipsis
232 $append_node = $dom->createTextNode( $append_string );
233 $node_removed_from->appendChild( $append_node );
234 $new_string = $dom->saveHTML( $body );
235 $new_string = mb_substr( $new_string, 6, -7, 'UTF-8' );
236 } elseif ( $append_string_length > 9 && XML_ELEMENT_NODE === $node->nodeType && 'p' == strtolower( $node->nodeName ) ) { // 9: '<p>X{\xE2\x80\xA6}</p>'
237 $new_string .= '<p>' . self::crop_str( $node->textContent, $append_string_length - 8 ) . '</p>';
238 }
239
240 // Clean up any empty Paragraphs that might have occurred after removing their children
241 return trim( preg_replace( '#<p>\s*</p>#i', '', $new_string ) );
242 }
243
244 function remove_innermost_last_child( $node, &$node_removed_from ) {
245 $node_removed_from = $node;
246
247 if ( !$node->lastChild ) {
248 return false;
249 }
250
251 if ( $node->lastChild->hasChildNodes() ) {
252 return self::remove_innermost_last_child( $node->lastChild, $node_removed_from );
253 }
254
255 $innermost_last_child = $node->lastChild;
256 $node->removeChild( $innermost_last_child );
257
258 return $innermost_last_child;
259 }
260
261 function bump_stats_extras_publicize_url( $bin, $post_id ) {
262 static $done = array();
263 if ( isset( $done[$post_id] ) ) {
264 return;
265 }
266 $done[$post_id] = true;
267
268 if ( function_exists( 'bump_stats_extras' ) )
269 bump_stats_extras( 'publicize_url', $bin );
270 }
271
272 public static function build_sprintf( $args ) {
273 $search = array();
274 $replace = array();
275 foreach ( $args as $k => $arg ) {
276 if ( 0 == $k ) {
277 $string = $arg;
278 continue;
279 }
280 $search[] = "%$arg%";
281 $replace[] = "%$k\$s";
282 }
283 return str_replace( $search, $replace, $string );
284 }
285 }
286