social-icons.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673
  1. <?php
  2. class Jetpack_Widget_Social_Icons extends WP_Widget {
  3. /**
  4. * @var array Default widget options.
  5. */
  6. protected $defaults;
  7. /**
  8. * Widget constructor.
  9. */
  10. public function __construct() {
  11. $widget_ops = array(
  12. 'classname' => 'jetpack_widget_social_icons',
  13. 'description' => __( 'Add social-media icons to your site.', 'jetpack' ),
  14. 'customize_selective_refresh' => true,
  15. );
  16. parent::__construct(
  17. 'jetpack_widget_social_icons',
  18. /** This filter is documented in modules/widgets/facebook-likebox.php */
  19. apply_filters( 'jetpack_widget_name', __( 'Social Icons', 'jetpack' ) ),
  20. $widget_ops
  21. );
  22. $this->defaults = array(
  23. 'title' => __( 'Follow Us', 'jetpack' ),
  24. 'icon-size' => 'medium',
  25. 'new-tab' => false,
  26. 'icons' => array(
  27. array(
  28. 'url' => '',
  29. ),
  30. ),
  31. );
  32. add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
  33. add_action( 'admin_print_footer_scripts', array( $this, 'render_admin_js' ) );
  34. add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_icon_scripts' ) );
  35. add_action( 'wp_footer', array( $this, 'include_svg_icons' ), 9999 );
  36. }
  37. /**
  38. * Script & styles for admin widget form.
  39. */
  40. public function enqueue_admin_scripts() {
  41. wp_enqueue_script( 'jetpack-widget-social-icons-script', plugins_url( 'social-icons/social-icons-admin.js', __FILE__ ), array( 'jquery-ui-sortable' ), '20170506' );
  42. wp_enqueue_style( 'jetpack-widget-social-icons-admin', plugins_url( 'social-icons/social-icons-admin.css', __FILE__ ), array(), '20170506' );
  43. }
  44. /**
  45. * Styles for front-end widget.
  46. */
  47. public function enqueue_icon_scripts() {
  48. wp_enqueue_style( 'jetpack-widget-social-icons-styles', plugins_url( 'social-icons/social-icons.css', __FILE__ ), array(), '20170506' );
  49. }
  50. /**
  51. * JavaScript for admin widget form.
  52. */
  53. public function render_admin_js() {
  54. global $wp_customize;
  55. global $pagenow;
  56. if ( ! isset( $wp_customize ) && 'widgets.php' !== $pagenow ) {
  57. return;
  58. }
  59. ?>
  60. <script type="text/html" id="tmpl-jetpack-widget-social-icons-template">
  61. <?php self::render_icons_template(); ?>
  62. </script>
  63. <?php
  64. }
  65. /**
  66. * Add SVG definitions to the footer.
  67. */
  68. public function include_svg_icons() {
  69. if ( ! is_active_widget( false, $this->id, $this->id_base, true ) ) {
  70. return;
  71. }
  72. // Define SVG sprite file in Jetpack
  73. $svg_icons = dirname( dirname( __FILE__ ) ) . '/theme-tools/social-menu/social-menu.svg';
  74. // Define SVG sprite file in WPCOM
  75. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
  76. $svg_icons = dirname( dirname( __FILE__ ) ) . '/social-menu/social-menu.svg';
  77. }
  78. // If it exists, include it.
  79. if ( is_file( $svg_icons ) ) {
  80. require_once( $svg_icons );
  81. }
  82. }
  83. /**
  84. * Front-end display of widget.
  85. *
  86. * @see WP_Widget::widget()
  87. *
  88. * @param array $args Widget arguments.
  89. * @param array $instance Saved values from database.
  90. */
  91. public function widget( $args, $instance ) {
  92. $instance = wp_parse_args( $instance, $this->defaults );
  93. /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
  94. $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base );
  95. echo $args['before_widget'];
  96. if ( ! empty( $title ) ) {
  97. echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
  98. }
  99. if ( ! empty( $instance['icons'] ) ) :
  100. // Get supported social icons.
  101. $social_icons = $this->get_supported_icons();
  102. $default_icon = $this->get_svg_icon( array( 'icon' => 'chain' ) );
  103. // Set target attribute for the link
  104. if ( true === $instance['new-tab'] ) {
  105. $target = '_blank';
  106. } else {
  107. $target = '_self';
  108. }
  109. ?>
  110. <ul class="jetpack-social-widget-list size-<?php echo esc_attr( $instance['icon-size'] ); ?>">
  111. <?php foreach ( $instance['icons'] as $icon ) : ?>
  112. <?php if ( ! empty( $icon['url'] ) ) : ?>
  113. <li class="jetpack-social-widget-item">
  114. <a href="<?php echo esc_url( $icon['url'], array( 'http', 'https', 'mailto', 'skype' ) ); ?>" target="<?php echo $target; ?>">
  115. <?php
  116. $found_icon = false;
  117. foreach( $social_icons as $social_icon ) {
  118. if ( false !== stripos( $icon['url'], $social_icon['url'] ) ) {
  119. echo '<span class="screen-reader-text">' . esc_attr( $social_icon['label'] ) . '</span>';
  120. echo $this->get_svg_icon( array( 'icon' => esc_attr( $social_icon['icon'] ) ) );
  121. $found_icon = true;
  122. break;
  123. }
  124. }
  125. if ( ! $found_icon ) {
  126. echo $default_icon;
  127. }
  128. ?>
  129. </a>
  130. </li>
  131. <?php endif; ?>
  132. <?php endforeach; ?>
  133. </ul>
  134. <?php
  135. endif;
  136. echo $args['after_widget'];
  137. /** This action is documented in modules/widgets/gravatar-profile.php */
  138. do_action( 'jetpack_stats_extra', 'widget_view', 'social_icons' );
  139. }
  140. /**
  141. * Sanitize widget form values as they are saved.
  142. *
  143. * @see WP_Widget::update()
  144. *
  145. * @param array $new_instance Values just sent to be saved.
  146. * @param array $old_instance Previously saved values from database.
  147. *
  148. * @return array Updated safe values to be saved.
  149. */
  150. public function update( $new_instance, $old_instance ) {
  151. $instance['title'] = sanitize_text_field( $new_instance['title'] );
  152. $instance['icon-size'] = $this->defaults['icon-size'];
  153. if ( in_array( $new_instance['icon-size'], array( 'small', 'medium', 'large' ) ) ) {
  154. $instance['icon-size'] = $new_instance['icon-size'];
  155. }
  156. $instance['new-tab'] = isset( $new_instance['new-tab'] ) ? (bool) $new_instance['new-tab'] : false;
  157. $icon_count = count( $new_instance['url-icons'] );
  158. $instance['icons'] = array();
  159. foreach( $new_instance['url-icons'] as $url ) {
  160. $url = filter_var( $url, FILTER_SANITIZE_URL );
  161. if ( ! empty( $url ) ) {
  162. $instance['icons'][] = array(
  163. 'url' => $url,
  164. );
  165. }
  166. }
  167. return $instance;
  168. }
  169. /**
  170. * Back-end widget form.
  171. *
  172. * @see WP_Widget::form()
  173. *
  174. * @param array $instance Previously saved values from database.
  175. *
  176. * @return string|void
  177. */
  178. public function form( $instance ) {
  179. $instance = wp_parse_args( $instance, $this->defaults );
  180. $title = sanitize_text_field( $instance['title'] );
  181. $sizes = array(
  182. 'small' => __( 'Small', 'jetpack' ),
  183. 'medium' => __( 'Medium', 'jetpack' ),
  184. 'large' => __( 'Large', 'jetpack' ),
  185. );
  186. $new_tab = isset( $instance['new-tab'] ) ? (bool) $instance['new-tab'] : false;
  187. ?>
  188. <p>
  189. <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php esc_html_e( 'Title:', 'jetpack' ); ?></label>
  190. <input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
  191. </p>
  192. <p>
  193. <label for="<?php echo $this->get_field_id( 'icon-size' ); ?>"><?php esc_html_e( 'Size:', 'jetpack' ); ?></label>
  194. <select class="widefat" name="<?php echo $this->get_field_name( 'icon-size' ); ?>">
  195. <?php foreach ( $sizes as $value => $label ) : ?>
  196. <option value="<?php echo esc_attr( $value ); ?>" <?php selected( $value, $instance['icon-size'] ); ?>><?php echo esc_attr( $label ); ?></option>
  197. <?php endforeach; ?>
  198. </select>
  199. </p>
  200. <div class="jetpack-social-icons-widget-list"
  201. data-url-icon-id="<?php echo $this->get_field_id( 'url-icons' ); ?>"
  202. data-url-icon-name="<?php echo $this->get_field_name( 'url-icons' ); ?>"
  203. >
  204. <?php
  205. foreach ( $instance['icons'] as $icon ) {
  206. self::render_icons_template( array(
  207. 'url-icon-id' => $this->get_field_id( 'url-icons' ),
  208. 'url-icon-name' => $this->get_field_name( 'url-icons' ),
  209. 'url-value' => $icon['url'],
  210. ) );
  211. }
  212. ?>
  213. </div>
  214. <p class="jetpack-social-icons-widget add-button">
  215. <button type="button" class="button jetpack-social-icons-add-button">
  216. <?php esc_html_e( 'Add an icon', 'jetpack' ); ?>
  217. </button>
  218. </p>
  219. <?php
  220. switch ( get_locale() ) {
  221. case 'es':
  222. $support = 'https://es.support.wordpress.com/social-media-icons-widget/#iconos-disponibles';
  223. break;
  224. case 'pt-br':
  225. $support = 'https://br.support.wordpress.com/widgets/widget-de-icones-sociais/#ícones-disponíveis';
  226. break;
  227. default:
  228. $support = 'https://en.support.wordpress.com/widgets/social-media-icons-widget/#available-icons';
  229. }
  230. ?>
  231. <p>
  232. <em><a href="<?php echo esc_url( $support ); ?>" target="_blank">
  233. <?php esc_html_e( 'View available icons', 'jetpack' ); ?>
  234. </a></em>
  235. </p>
  236. <p>
  237. <input type="checkbox" class="checkbox" id="<?php echo $this->get_field_id( 'new-tab' ); ?>" name="<?php echo $this->get_field_name( 'new-tab' ); ?>" <?php checked( $new_tab ); ?> />
  238. <label for="<?php echo $this->get_field_id( 'new-tab' ); ?>"><?php esc_html_e( 'Open link in a new tab', 'jetpack' ); ?></label>
  239. </p>
  240. <?php
  241. }
  242. /**
  243. * Generates template to add icons.
  244. *
  245. * @param array $args Template arguments
  246. */
  247. static function render_icons_template( $args = array() ) {
  248. $defaults = array(
  249. 'url-icon-id' => '',
  250. 'url-icon-name' => '',
  251. 'url-value' => '',
  252. );
  253. $args = wp_parse_args( $args, $defaults );
  254. ?>
  255. <div class="jetpack-social-icons-widget-item">
  256. <div class="jetpack-social-icons-widget-item-wrapper">
  257. <div class="handle"></div>
  258. <p class="jetpack-widget-social-icons-url">
  259. <?php
  260. printf( '<input class="widefat id="%1$s" name="%2$s[]" type="text" placeholder="%3$s" value="%4$s"/>',
  261. esc_attr( $args['url-icon-id'] ),
  262. esc_attr( $args['url-icon-name'] ),
  263. esc_attr__( 'Account URL', 'jetpack' ),
  264. esc_url( $args['url-value'], array( 'http', 'https', 'mailto', 'skype' ) )
  265. );
  266. ?>
  267. </p>
  268. <p class="jetpack-widget-social-icons-remove-item">
  269. <a class="jetpack-widget-social-icons-remove-item-button" href="javascript:;">
  270. <?php esc_html_e( 'Remove', 'jetpack' ); ?>
  271. </a>
  272. </p>
  273. </div>
  274. </div>
  275. <?php
  276. }
  277. /**
  278. * Return SVG markup.
  279. *
  280. * @param array $args {
  281. * Parameters needed to display an SVG.
  282. *
  283. * @type string $icon Required SVG icon filename.
  284. * }
  285. * @return string SVG markup.
  286. */
  287. public function get_svg_icon( $args = array() ) {
  288. // Make sure $args are an array.
  289. if ( empty( $args ) ) {
  290. return esc_html__( 'Please define default parameters in the form of an array.', 'jetpack' );
  291. }
  292. // Set defaults.
  293. $defaults = array(
  294. 'icon' => '',
  295. );
  296. // Parse args.
  297. $args = wp_parse_args( $args, $defaults );
  298. // Define an icon.
  299. if ( false === array_key_exists( 'icon', $args ) ) {
  300. return esc_html__( 'Please define an SVG icon filename.', 'jetpack' );
  301. }
  302. // Set aria hidden.
  303. $aria_hidden = ' aria-hidden="true"';
  304. // Begin SVG markup.
  305. $svg = '<svg class="icon icon-' . esc_attr( $args['icon'] ) . '"' . $aria_hidden . ' role="img">';
  306. /*
  307. * Display the icon.
  308. *
  309. * The whitespace around `<use>` is intentional - it is a work around to a keyboard navigation bug in Safari 10.
  310. *
  311. * See https://core.trac.wordpress.org/ticket/38387.
  312. */
  313. $svg .= ' <use href="#icon-' . esc_html( $args['icon'] ) . '" xlink:href="#icon-' . esc_html( $args['icon'] ) . '"></use> ';
  314. $svg .= '</svg>';
  315. return $svg;
  316. }
  317. /**
  318. * Returns an array of supported social links (URL, icon, and label).
  319. *
  320. * @return array $social_links_icons
  321. */
  322. public function get_supported_icons() {
  323. $social_links_icons = array(
  324. array(
  325. 'url' => '500px.com',
  326. 'icon' => '500px',
  327. 'label' => '500px',
  328. ),
  329. array(
  330. 'url' => 'amazon.cn',
  331. 'icon' => 'amazon',
  332. 'label' => 'Amazon',
  333. ),
  334. array(
  335. 'url' => 'amazon.in',
  336. 'icon' => 'amazon',
  337. 'label' => 'Amazon',
  338. ),
  339. array(
  340. 'url' => 'amazon.fr',
  341. 'icon' => 'amazon',
  342. 'label' => 'Amazon',
  343. ),
  344. array(
  345. 'url' => 'amazon.de',
  346. 'icon' => 'amazon',
  347. 'label' => 'Amazon',
  348. ),
  349. array(
  350. 'url' => 'amazon.it',
  351. 'icon' => 'amazon',
  352. 'label' => 'Amazon',
  353. ),
  354. array(
  355. 'url' => 'amazon.nl',
  356. 'icon' => 'amazon',
  357. 'label' => 'Amazon',
  358. ),
  359. array(
  360. 'url' => 'amazon.es',
  361. 'icon' => 'amazon',
  362. 'label' => 'Amazon',
  363. ),
  364. array(
  365. 'url' => 'amazon.co',
  366. 'icon' => 'amazon',
  367. 'label' => 'Amazon',
  368. ),
  369. array(
  370. 'url' => 'amazon.ca',
  371. 'icon' => 'amazon',
  372. 'label' => 'Amazon',
  373. ),
  374. array(
  375. 'url' => 'amazon.com',
  376. 'icon' => 'amazon',
  377. 'label' => 'Amazon',
  378. ),
  379. array(
  380. 'url' => 'apple.com',
  381. 'icon' => 'apple',
  382. 'label' => 'Apple',
  383. ),
  384. array(
  385. 'url' => 'itunes.com',
  386. 'icon' => 'apple',
  387. 'label' => 'iTunes',
  388. ),
  389. array(
  390. 'url' => 'bandcamp.com',
  391. 'icon' => 'bandcamp',
  392. 'label' => 'Bandcamp',
  393. ),
  394. array(
  395. 'url' => 'behance.net',
  396. 'icon' => 'behance',
  397. 'label' => 'Behance',
  398. ),
  399. array(
  400. 'url' => 'codepen.io',
  401. 'icon' => 'codepen',
  402. 'label' => 'CodePen',
  403. ),
  404. array(
  405. 'url' => 'deviantart.com',
  406. 'icon' => 'deviantart',
  407. 'label' => 'DeviantArt',
  408. ),
  409. array(
  410. 'url' => 'digg.com',
  411. 'icon' => 'digg',
  412. 'label' => 'Digg',
  413. ),
  414. array(
  415. 'url' => 'dribbble.com',
  416. 'icon' => 'dribbble',
  417. 'label' => 'Dribbble',
  418. ),
  419. array(
  420. 'url' => 'dropbox.com',
  421. 'icon' => 'dropbox',
  422. 'label' => 'Dropbox',
  423. ),
  424. array(
  425. 'url' => 'etsy.com',
  426. 'icon' => 'etsy',
  427. 'label' => 'Etsy',
  428. ),
  429. array(
  430. 'url' => 'facebook.com',
  431. 'icon' => 'facebook',
  432. 'label' => 'Facebook',
  433. ),
  434. array(
  435. 'url' => '/feed/',
  436. 'icon' => 'feed',
  437. 'label' => __( 'RSS Feed', 'jetpack' ),
  438. ),
  439. array(
  440. 'url' => 'flickr.com',
  441. 'icon' => 'flickr',
  442. 'label' => 'Flickr',
  443. ),
  444. array(
  445. 'url' => 'foursquare.com',
  446. 'icon' => 'foursquare',
  447. 'label' => 'Foursquare',
  448. ),
  449. array(
  450. 'url' => 'goodreads.com',
  451. 'icon' => 'goodreads',
  452. 'label' => 'Goodreads',
  453. ),
  454. array(
  455. 'url' => 'google.com/+',
  456. 'icon' => 'google-plus',
  457. 'label' => 'Google +',
  458. ),
  459. array(
  460. 'url' => 'plus.google.com',
  461. 'icon' => 'google-plus',
  462. 'label' => 'Google +',
  463. ),
  464. array(
  465. 'url' => 'google.com',
  466. 'icon' => 'google',
  467. 'label' => 'Google',
  468. ),
  469. array(
  470. 'url' => 'github.com',
  471. 'icon' => 'github',
  472. 'label' => 'GitHub',
  473. ),
  474. array(
  475. 'url' => 'instagram.com',
  476. 'icon' => 'instagram',
  477. 'label' => 'Instagram',
  478. ),
  479. array(
  480. 'url' => 'linkedin.com',
  481. 'icon' => 'linkedin',
  482. 'label' => 'LinkedIn',
  483. ),
  484. array(
  485. 'url' => 'mailto:',
  486. 'icon' => 'mail',
  487. 'label' => __( 'Email', 'jetpack' ),
  488. ),
  489. array(
  490. 'url' => 'meetup.com',
  491. 'icon' => 'meetup',
  492. 'label' => 'Meetup',
  493. ),
  494. array(
  495. 'url' => 'medium.com',
  496. 'icon' => 'medium',
  497. 'label' => 'Medium',
  498. ),
  499. array(
  500. 'url' => 'pinterest.com',
  501. 'icon' => 'pinterest',
  502. 'label' => 'Pinterest',
  503. ),
  504. array(
  505. 'url' => 'getpocket.com',
  506. 'icon' => 'pocket',
  507. 'label' => 'Pocket',
  508. ),
  509. array(
  510. 'url' => 'reddit.com',
  511. 'icon' => 'reddit',
  512. 'label' => 'Reddit',
  513. ),
  514. array(
  515. 'url' => 'skype.com',
  516. 'icon' => 'skype',
  517. 'label' => 'Skype',
  518. ),
  519. array(
  520. 'url' => 'skype:',
  521. 'icon' => 'skype',
  522. 'label' => 'Skype',
  523. ),
  524. array(
  525. 'url' => 'slideshare.net',
  526. 'icon' => 'slideshare',
  527. 'label' => 'SlideShare',
  528. ),
  529. array(
  530. 'url' => 'snapchat.com',
  531. 'icon' => 'snapchat',
  532. 'label' => 'Snapchat',
  533. ),
  534. array(
  535. 'url' => 'soundcloud.com',
  536. 'icon' => 'soundcloud',
  537. 'label' => 'SoundCloud',
  538. ),
  539. array(
  540. 'url' => 'spotify.com',
  541. 'icon' => 'spotify',
  542. 'label' => 'Spotify',
  543. ),
  544. array(
  545. 'url' => 'stumbleupon.com',
  546. 'icon' => 'stumbleupon',
  547. 'label' => 'StumbleUpon',
  548. ),
  549. array(
  550. 'url' => 'tumblr.com',
  551. 'icon' => 'tumblr',
  552. 'label' => 'Tumblr',
  553. ),
  554. array(
  555. 'url' => 'twitch.tv',
  556. 'icon' => 'twitch',
  557. 'label' => 'Twitch',
  558. ),
  559. array(
  560. 'url' => 'twitter.com',
  561. 'icon' => 'twitter',
  562. 'label' => 'Twitter',
  563. ),
  564. array(
  565. 'url' => 'vimeo.com',
  566. 'icon' => 'vimeo',
  567. 'label' => 'Vimeo',
  568. ),
  569. array(
  570. 'url' => 'vk.com',
  571. 'icon' => 'vk',
  572. 'label' => 'VK',
  573. ),
  574. array(
  575. 'url' => 'wordpress.com',
  576. 'icon' => 'wordpress',
  577. 'label' => 'WordPress.com',
  578. ),
  579. array(
  580. 'url' => 'wordpress.org',
  581. 'icon' => 'wordpress',
  582. 'label' => 'WordPress',
  583. ),
  584. array(
  585. 'url' => 'yelp.com',
  586. 'icon' => 'yelp',
  587. 'label' => 'Yelp',
  588. ),
  589. array(
  590. 'url' => 'youtube.com',
  591. 'icon' => 'youtube',
  592. 'label' => 'YouTube',
  593. ),
  594. );
  595. return $social_links_icons;
  596. }
  597. } // Jetpack_Widget_Social_Icons
  598. /**
  599. * Register and load the widget.
  600. *
  601. * @access public
  602. * @return void
  603. */
  604. function jetpack_widget_social_icons_load() {
  605. register_widget( 'Jetpack_Widget_Social_Icons' );
  606. }
  607. add_action( 'widgets_init', 'jetpack_widget_social_icons_load' );