No Description

likes.php 24KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702
  1. <?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
  2. /**
  3. * Module Name: Likes
  4. * Module Description: Give visitors an easy way to show they appreciate your content.
  5. * First Introduced: 2.2
  6. * Sort Order: 23
  7. * Requires Connection: Yes
  8. * Auto Activate: No
  9. * Module Tags: Social
  10. * Feature: Engagement
  11. * Additional Search Queries: like, likes, wordpress.com
  12. *
  13. * @package automattic/jetpack
  14. */
  15. use Automattic\Jetpack\Assets;
  16. Assets::add_resource_hint(
  17. array(
  18. '//widgets.wp.com',
  19. '//s0.wp.com',
  20. '//0.gravatar.com',
  21. '//1.gravatar.com',
  22. '//2.gravatar.com',
  23. ),
  24. 'dns-prefetch'
  25. );
  26. require_once __DIR__ . '/likes/jetpack-likes-master-iframe.php';
  27. require_once __DIR__ . '/likes/jetpack-likes-settings.php';
  28. /**
  29. * Jetpack Like Class
  30. */
  31. class Jetpack_Likes {
  32. /**
  33. * Initialize class
  34. */
  35. public static function init() {
  36. static $instance = null;
  37. if ( ! $instance ) {
  38. $instance = new Jetpack_Likes();
  39. }
  40. return $instance;
  41. }
  42. /**
  43. * Constructs Likes class
  44. */
  45. public function __construct() {
  46. $this->in_jetpack = ( defined( 'IS_WPCOM' ) && IS_WPCOM ) ? false : true;
  47. $this->settings = new Jetpack_Likes_Settings();
  48. // We need to run on wp hook rather than init because we check is_amp_endpoint()
  49. // when bootstrapping hooks.
  50. add_action( 'wp', array( $this, 'action_init' ), 99 );
  51. add_action( 'admin_init', array( $this, 'admin_init' ) );
  52. if ( $this->in_jetpack ) {
  53. add_action( 'jetpack_activate_module_likes', array( $this, 'set_social_notifications_like' ) );
  54. add_action( 'jetpack_deactivate_module_likes', array( $this, 'delete_social_notifications_like' ) );
  55. Jetpack::enable_module_configurable( __FILE__ );
  56. add_filter( 'jetpack_module_configuration_url_likes', array( $this, 'jetpack_likes_configuration_url' ) );
  57. add_action( 'admin_print_scripts-settings_page_sharing', array( $this, 'load_jp_css' ) );
  58. add_filter( 'sharing_show_buttons_on_row_start', array( $this, 'configuration_target_area' ) );
  59. $active = Jetpack::get_active_modules();
  60. if ( ! in_array( 'sharedaddy', $active, true ) && ! in_array( 'publicize', $active, true ) ) {
  61. // we don't have a sharing page yet.
  62. add_action( 'admin_menu', array( $this->settings, 'sharing_menu' ) );
  63. }
  64. if ( in_array( 'publicize', $active, true ) && ! in_array( 'sharedaddy', $active, true ) ) {
  65. // we have a sharing page but not the global options area.
  66. add_action( 'pre_admin_screen_sharing', array( $this->settings, 'sharing_block' ), 20 );
  67. add_action( 'pre_admin_screen_sharing', array( $this->settings, 'updated_message' ), -10 );
  68. }
  69. if ( ! in_array( 'sharedaddy', $active, true ) ) {
  70. add_action( 'admin_init', array( $this->settings, 'process_update_requests_if_sharedaddy_not_loaded' ) );
  71. add_action( 'sharing_global_options', array( $this->settings, 'admin_settings_showbuttonon_init' ), 19 );
  72. add_action( 'sharing_admin_update', array( $this->settings, 'admin_settings_showbuttonon_callback' ), 19 );
  73. add_action( 'admin_init', array( $this->settings, 'add_meta_box' ) );
  74. } else {
  75. add_filter( 'sharing_meta_box_title', array( $this->settings, 'add_likes_to_sharing_meta_box_title' ) );
  76. add_action( 'start_sharing_meta_box_content', array( $this->settings, 'meta_box_content' ) );
  77. }
  78. } else { // wpcom.
  79. add_action( 'wpmu_new_blog', array( $this, 'enable_comment_likes' ), 10, 1 );
  80. add_action( 'admin_init', array( $this->settings, 'add_meta_box' ) );
  81. add_action( 'end_likes_meta_box_content', array( $this->settings, 'sharing_meta_box_content' ) );
  82. add_filter( 'likes_meta_box_title', array( $this->settings, 'add_likes_to_sharing_meta_box_title' ) );
  83. }
  84. add_action( 'admin_init', array( $this, 'admin_discussion_likes_settings_init' ) ); // Likes notifications.
  85. add_action( 'admin_bar_menu', array( $this, 'admin_bar_likes' ), 60 );
  86. add_action( 'wp_enqueue_scripts', array( $this, 'load_styles_register_scripts' ) );
  87. add_action( 'save_post', array( $this->settings, 'meta_box_save' ) );
  88. add_action( 'edit_attachment', array( $this->settings, 'meta_box_save' ) );
  89. add_action( 'sharing_global_options', array( $this->settings, 'admin_settings_init' ), 20 );
  90. add_action( 'sharing_admin_update', array( $this->settings, 'admin_settings_callback' ), 20 );
  91. }
  92. /**
  93. * Set the social_notifications_like option to `on` when the Likes module is activated.
  94. *
  95. * @since 3.7.0
  96. */
  97. public function set_social_notifications_like() {
  98. update_option( 'social_notifications_like', 'on' );
  99. }
  100. /**
  101. * Delete the social_notifications_like option that was set to `on` on module activation.
  102. *
  103. * @since 3.7.0
  104. */
  105. public function delete_social_notifications_like() {
  106. delete_option( 'social_notifications_like' );
  107. }
  108. /**
  109. * Overrides default configuration url
  110. *
  111. * @uses admin_url
  112. * @return string module settings URL
  113. */
  114. public function jetpack_likes_configuration_url() {
  115. return admin_url( 'options-general.php?page=sharing#likes' );
  116. }
  117. /**
  118. * Loads Jetpack's CSS on the sharing page so we can use .jetpack-targetable
  119. */
  120. public function load_jp_css() {
  121. /**
  122. * Do we really need `admin_styles`? With the new admin UI, it's breaking some bits.
  123. * Jetpack::init()->admin_styles();
  124. */
  125. }
  126. /**
  127. * Load scripts and styles for front end.
  128. */
  129. public function load_styles_register_scripts() {
  130. if ( $this->in_jetpack ) {
  131. wp_enqueue_style( 'jetpack_likes', plugins_url( 'likes/style.css', __FILE__ ), array(), JETPACK__VERSION );
  132. $this->register_scripts();
  133. }
  134. }
  135. /**
  136. * Stub for is_post_likeable, since some wpcom functions call this directly on the class
  137. * Are likes enabled for this post?
  138. *
  139. * @param int $post_id id of the post.
  140. * @return bool
  141. */
  142. public static function is_post_likeable( $post_id = 0 ) {
  143. _deprecated_function( __METHOD__, 'jetpack-5.4', 'Jetpack_Likes_Settings()->is_post_likeable' );
  144. $settings = new Jetpack_Likes_Settings();
  145. return $settings->is_post_likeable( $post_id );
  146. }
  147. /**
  148. * Stub for is_likes_visible, since some themes were calling it directly from this class
  149. *
  150. * @deprecated 5.4
  151. * @return bool
  152. */
  153. public function is_likes_visible() {
  154. _deprecated_function( __METHOD__, 'jetpack-5.4', 'Jetpack_Likes_Settings()->is_likes_visible' );
  155. $settings = new Jetpack_Likes_Settings();
  156. return $settings->is_likes_visible();
  157. }
  158. /**
  159. * Adds in the jetpack-targetable class so when we visit sharing#likes our like settings get highlighted by a yellow box
  160. *
  161. * @param string $html row heading for the sharedaddy "which page" setting.
  162. * @return string $html with the jetpack-targetable class and likes id. tbody gets closed after the like settings
  163. */
  164. public function configuration_target_area( $html = '' ) {
  165. $html = "<tbody id='likes' class='jetpack-targetable'>" . $html;
  166. return $html;
  167. }
  168. /**
  169. * Options to be added to the discussion page (see also admin_settings_init, etc below for Sharing settings page)
  170. */
  171. public function admin_discussion_likes_settings_init() {
  172. // Add a temporary section, until we can move the setting out of there and with the rest of the email notification settings.
  173. add_settings_section( 'likes-notifications', __( 'Likes Notifications', 'jetpack' ), array( $this, 'admin_discussion_likes_settings_section' ), 'discussion' );
  174. add_settings_field( 'social-notifications', __( 'Email me whenever', 'jetpack' ), array( $this, 'admin_discussion_likes_settings_field' ), 'discussion', 'likes-notifications' );
  175. // Register the setting.
  176. register_setting( 'discussion', 'social_notifications_like', array( $this, 'admin_discussion_likes_settings_validate' ) );
  177. }
  178. /** Add email notification options to WordPress discussion settings */
  179. public function admin_discussion_likes_settings_section() {
  180. // Atypical usage here. We emit jquery to move likes notification checkbox to be with the rest of the email notification settings.
  181. ?>
  182. <script type="text/javascript">
  183. jQuery( function( $ ) {
  184. var table = $( '#social_notifications_like' ).parents( 'table:first' ),
  185. header = table.prevAll( 'h2:first' ),
  186. newParent = $( '#moderation_notify' ).parent( 'label' ).parent();
  187. if ( !table.length || !header.length || !newParent.length ) {
  188. return;
  189. }
  190. newParent.append( '<br/>' ).append( table.end().parent( 'label' ).siblings().andSelf() );
  191. header.remove();
  192. table.remove();
  193. } );
  194. </script>
  195. <?php
  196. }
  197. /** Check if email notifications for likes is on or off.
  198. *
  199. * @param string $option - which option we're checking (social_notifications_like).
  200. */
  201. public function admin_likes_get_option( $option ) {
  202. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
  203. $option_setting = get_blog_option( get_current_blog_id(), $option, 'on' );
  204. } else {
  205. $option_setting = get_option( $option, 'on' );
  206. }
  207. return (int) ( 'on' === $option_setting );
  208. }
  209. /** Display email notification for likes setting in WordPress' discussion settings. */
  210. public function admin_discussion_likes_settings_field() {
  211. $like = $this->admin_likes_get_option( 'social_notifications_like' );
  212. ?>
  213. <label><input type="checkbox" id="social_notifications_like" name="social_notifications_like" value="1" <?php checked( $like ); ?> /> <?php esc_html_e( 'Someone likes one of my posts', 'jetpack' ); ?></label>
  214. <?php
  215. }
  216. /**
  217. * Validate email notification settings.
  218. *
  219. * @param string $input - determines if checbox is on or off.
  220. */
  221. public function admin_discussion_likes_settings_validate( $input ) {
  222. // If it's not set (was unchecked during form submission) or was set to off (during option update), return 'off'.
  223. if ( ! $input || 'off' === $input ) {
  224. return 'off';
  225. }
  226. // Otherwise return 'on'.
  227. return 'on';
  228. }
  229. /** Initialize admin settings */
  230. public function admin_init() {
  231. add_filter( 'manage_posts_columns', array( $this, 'add_like_count_column' ) );
  232. add_filter( 'manage_pages_columns', array( $this, 'add_like_count_column' ) );
  233. add_action( 'manage_posts_custom_column', array( $this, 'likes_edit_column' ), 10, 2 );
  234. add_action( 'manage_pages_custom_column', array( $this, 'likes_edit_column' ), 10, 2 );
  235. add_action( 'admin_print_styles-edit.php', array( $this, 'load_admin_css' ) );
  236. add_action( 'admin_print_scripts-edit.php', array( $this, 'enqueue_admin_scripts' ) );
  237. }
  238. /** Initialize action */
  239. public function action_init() {
  240. if ( is_admin() || ! $this->settings->is_likes_visible() ) {
  241. return;
  242. }
  243. if ( ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) ||
  244. ( defined( 'APP_REQUEST' ) && APP_REQUEST ) ||
  245. ( defined( 'REST_API_REQUEST' ) && REST_API_REQUEST ) ||
  246. ( defined( 'COOKIE_AUTH_REQUEST' ) && COOKIE_AUTH_REQUEST ) ||
  247. ( defined( 'JABBER_SERVER' ) && JABBER_SERVER ) ) {
  248. return;
  249. }
  250. if (
  251. class_exists( 'Jetpack_AMP_Support' )
  252. && Jetpack_AMP_Support::is_amp_request()
  253. ) {
  254. return;
  255. }
  256. if ( $this->in_jetpack ) {
  257. add_filter( 'the_content', array( $this, 'post_likes' ), 30, 1 );
  258. add_filter( 'the_excerpt', array( $this, 'post_likes' ), 30, 1 );
  259. } else {
  260. add_filter( 'post_flair', array( $this, 'post_likes' ), 30, 1 );
  261. add_filter( 'post_flair_block_css', array( $this, 'post_flair_service_enabled_like' ) );
  262. wp_enqueue_script( 'postmessage', '/wp-content/js/postmessage.js', array(), JETPACK__VERSION, true );
  263. wp_enqueue_script( 'jetpack_resize', '/wp-content/js/jquery/jquery.jetpack-resize.js', array( 'jquery' ), JETPACK__VERSION, true );
  264. wp_enqueue_script( 'jetpack_likes_queuehandler', plugins_url( 'queuehandler.js', __FILE__ ), array( 'jquery', 'postmessage', 'jetpack_resize' ), JETPACK__VERSION, true );
  265. wp_enqueue_style( 'jetpack_likes', plugins_url( 'jetpack-likes.css', __FILE__ ), array(), JETPACK__VERSION );
  266. }
  267. }
  268. /**
  269. * Register scripts.
  270. */
  271. public function register_scripts() {
  272. wp_register_script(
  273. 'postmessage',
  274. Assets::get_file_url_for_environment( '_inc/build/postmessage.min.js', '_inc/postmessage.js' ),
  275. array(),
  276. JETPACK__VERSION,
  277. true
  278. );
  279. wp_register_script(
  280. 'jetpack_resize',
  281. Assets::get_file_url_for_environment(
  282. '_inc/build/jquery.jetpack-resize.min.js',
  283. '_inc/jquery.jetpack-resize.js'
  284. ),
  285. array( 'jquery' ),
  286. JETPACK__VERSION,
  287. true
  288. );
  289. wp_register_script(
  290. 'jetpack_likes_queuehandler',
  291. Assets::get_file_url_for_environment(
  292. '_inc/build/likes/queuehandler.min.js',
  293. 'modules/likes/queuehandler.js'
  294. ),
  295. array( 'jquery', 'postmessage', 'jetpack_resize' ),
  296. JETPACK__VERSION,
  297. true
  298. );
  299. }
  300. /**
  301. * Load the CSS needed for the wp-admin area.
  302. */
  303. public function load_admin_css() {
  304. ?>
  305. <style type="text/css">
  306. .vers img { display: none; }
  307. .metabox-prefs .vers img { display: inline; }
  308. .fixed .column-likes { width: 5.5em; padding: 8px 0; text-align: left; }
  309. .fixed .column-stats { width: 5em; }
  310. .fixed .column-likes .post-com-count {
  311. -webkit-box-sizing: border-box;
  312. -moz-box-sizing: border-box;
  313. box-sizing: border-box;
  314. display: inline-block;
  315. padding: 0 8px;
  316. height: 2em;
  317. margin-top: 5px;
  318. -webkit-border-radius: 5px;
  319. border-radius: 5px;
  320. background-color: #787c82;
  321. color: #FFF;
  322. font-size: 11px;
  323. line-height: 21px;
  324. }
  325. .fixed .column-likes .post-com-count::after { border: none !important; }
  326. .fixed .column-likes .post-com-count:hover { background-color: #2271b1; }
  327. .fixed .column-likes .vers:before {
  328. font: normal 20px/1 dashicons;
  329. content: '\f155';
  330. speak: none;
  331. -webkit-font-smoothing: antialiased;
  332. -moz-osx-font-smoothing: grayscale;
  333. }
  334. @media screen and (max-width: 782px) {
  335. .fixed .column-likes {
  336. display: none;
  337. }
  338. }
  339. </style>
  340. <?php
  341. }
  342. /**
  343. * Load the JS required for loading the like counts.
  344. */
  345. public function enqueue_admin_scripts() {
  346. if ( empty( $_GET['post_type'] ) || 'post' === $_GET['post_type'] || 'page' === $_GET['post_type'] ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
  347. if ( $this->in_jetpack ) {
  348. wp_enqueue_script(
  349. 'likes-post-count',
  350. Assets::get_file_url_for_environment(
  351. '_inc/build/likes/post-count.min.js',
  352. 'modules/likes/post-count.js'
  353. ),
  354. array( 'jquery' ),
  355. JETPACK__VERSION,
  356. $in_footer = false
  357. );
  358. wp_enqueue_script(
  359. 'likes-post-count-jetpack',
  360. Assets::get_file_url_for_environment(
  361. '_inc/build/likes/post-count-jetpack.min.js',
  362. 'modules/likes/post-count-jetpack.js'
  363. ),
  364. array( 'likes-post-count' ),
  365. JETPACK__VERSION,
  366. $in_footer = false
  367. );
  368. } else {
  369. wp_enqueue_script( 'jquery.wpcom-proxy-request', '/wp-content/js/jquery/jquery.wpcom-proxy-request.js', array( 'jquery' ), JETPACK__VERSION, true );
  370. wp_enqueue_script( 'likes-post-count', plugins_url( 'likes/post-count.js', __DIR__ ), array( 'jquery' ), JETPACK__VERSION, $in_footer = false );
  371. wp_enqueue_script( 'likes-post-count-wpcom', plugins_url( 'likes/post-count-wpcom.js', __DIR__ ), array( 'likes-post-count', 'jquery.wpcom-proxy-request' ), JETPACK__VERSION, $in_footer = false );
  372. }
  373. }
  374. }
  375. /**
  376. * Add "Likes" column data to the post edit table in wp-admin.
  377. *
  378. * @param string $column_name - name of the column.
  379. * @param int $post_id - the post id.
  380. */
  381. public function likes_edit_column( $column_name, $post_id ) {
  382. if ( 'likes' === $column_name ) {
  383. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
  384. $blog_id = get_current_blog_id();
  385. } else {
  386. $blog_id = Jetpack_Options::get_option( 'id' );
  387. }
  388. $permalink = get_permalink( get_the_ID() );
  389. ?>
  390. <a title="" data-post-id="<?php echo (int) $post_id; ?>" class="post-com-count post-like-count" id="post-like-count-<?php echo (int) $post_id; ?>" data-blog-id="<?php echo (int) $blog_id; ?>" href="<?php echo esc_url( $permalink ); ?>#like-<?php echo (int) $post_id; ?>">
  391. <span class="comment-count">0</span>
  392. </a>
  393. <?php
  394. }
  395. }
  396. /**
  397. * Add a "Likes" column header to the post edit table in wp-admin.
  398. *
  399. * @param array $columns - array of columns in wp-admin.
  400. */
  401. public function add_like_count_column( $columns ) {
  402. $date = $columns['date'];
  403. unset( $columns['date'] );
  404. $columns['likes'] = '<span class="vers"><img title="' . esc_attr__( 'Likes', 'jetpack' ) . '" alt="' . esc_attr__( 'Likes', 'jetpack' ) . '" src="//s0.wordpress.com/i/like-grey-icon.png" /><span class="screen-reader-text">' . __( 'Likes', 'jetpack' ) . '</span></span>';
  405. $columns['date'] = $date;
  406. return $columns;
  407. }
  408. /**
  409. * Append like button to content.
  410. *
  411. * @param string $content - content of the page.
  412. */
  413. public function post_likes( $content ) {
  414. $post_id = get_the_ID();
  415. if ( ! is_numeric( $post_id ) || ! $this->settings->is_likes_visible() ) {
  416. return $content;
  417. }
  418. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
  419. $blog_id = get_current_blog_id();
  420. $bloginfo = get_blog_details( (int) $blog_id );
  421. $domain = $bloginfo->domain;
  422. } else {
  423. $blog_id = Jetpack_Options::get_option( 'id' );
  424. $url = home_url();
  425. $url_parts = wp_parse_url( $url );
  426. $domain = $url_parts['host'];
  427. }
  428. // Make sure to include the scripts before the iframe otherwise weird things happen.
  429. add_action( 'wp_footer', 'jetpack_likes_master_iframe', 21 );
  430. /**
  431. * If the same post appears more then once on a page the page goes crazy
  432. * we need a slightly more unique id / name for the widget wrapper.
  433. */
  434. $uniqid = uniqid();
  435. $src = sprintf( 'https://widgets.wp.com/likes/#blog_id=%1$d&amp;post_id=%2$d&amp;origin=%3$s&amp;obj_id=%1$d-%2$d-%4$s', $blog_id, $post_id, $domain, $uniqid );
  436. $name = sprintf( 'like-post-frame-%1$d-%2$d-%3$s', $blog_id, $post_id, $uniqid );
  437. $wrapper = sprintf( 'like-post-wrapper-%1$d-%2$d-%3$s', $blog_id, $post_id, $uniqid );
  438. $headline = sprintf(
  439. /** This filter is already documented in modules/sharedaddy/sharing-service.php */
  440. apply_filters( 'jetpack_sharing_headline_html', '<h3 class="sd-title">%s</h3>', esc_html__( 'Like this:', 'jetpack' ), 'likes' ),
  441. esc_html__( 'Like this:', 'jetpack' )
  442. );
  443. $title = esc_html__( 'Like or Reblog', 'jetpack' );
  444. $html = "<div class='sharedaddy sd-block sd-like jetpack-likes-widget-wrapper jetpack-likes-widget-unloaded' id='$wrapper' data-src='$src' data-name='$name' data-title='$title'>";
  445. $html .= $headline;
  446. $html .= "<div class='likes-widget-placeholder post-likes-widget-placeholder' style='height: 55px;'><span class='button'><span>" . esc_html__( 'Like', 'jetpack' ) . '</span></span> <span class="loading">' . esc_html__( 'Loading...', 'jetpack' ) . '</span></div>';
  447. $html .= "<span class='sd-text-color'></span><a class='sd-link-color'></a>";
  448. $html .= '</div>';
  449. // Let's make sure that the script is enqueued.
  450. wp_enqueue_script( 'jetpack_likes_queuehandler' );
  451. return $content . $html;
  452. }
  453. /**
  454. * Adds sd-like-enabled CSS class
  455. *
  456. * @param array $classes CSS class for post flair.
  457. */
  458. public function post_flair_service_enabled_like( $classes ) {
  459. $classes[] = 'sd-like-enabled';
  460. return $classes;
  461. }
  462. /** Checks if admin bar is visible.*/
  463. public function is_admin_bar_button_visible() {
  464. global $wp_admin_bar;
  465. if ( ! is_object( $wp_admin_bar ) ) {
  466. return false;
  467. }
  468. if ( ( ! is_singular( 'post' ) && ! is_attachment() && ! is_page() ) ) {
  469. return false;
  470. }
  471. if ( ! $this->settings->is_likes_visible() ) {
  472. return false;
  473. }
  474. if ( ! $this->settings->is_post_likeable() ) {
  475. return false;
  476. }
  477. /**
  478. * Filters whether the Like button is enabled in the admin bar.
  479. *
  480. * @module likes
  481. *
  482. * @since 2.2.0
  483. *
  484. * @param bool true Should the Like button be visible in the Admin bar. Default to true.
  485. */
  486. return (bool) apply_filters( 'jetpack_admin_bar_likes_enabled', true );
  487. }
  488. /** Adds like section in admin bar. */
  489. public function admin_bar_likes() {
  490. global $wp_admin_bar;
  491. $post_id = get_the_ID();
  492. if ( ! is_numeric( $post_id ) || ! $this->is_admin_bar_button_visible() ) {
  493. return;
  494. }
  495. $protocol = 'http';
  496. if ( is_ssl() ) {
  497. $protocol = 'https';
  498. }
  499. if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
  500. $blog_id = get_current_blog_id();
  501. $bloginfo = get_blog_details( (int) $blog_id );
  502. $domain = $bloginfo->domain;
  503. } else {
  504. $blog_id = Jetpack_Options::get_option( 'id' );
  505. $url = home_url();
  506. $url_parts = wp_parse_url( $url );
  507. $domain = $url_parts['host'];
  508. }
  509. // Make sure to include the scripts before the iframe otherwise weird things happen.
  510. add_action( 'wp_footer', 'jetpack_likes_master_iframe', 21 );
  511. $src = sprintf( 'https://widgets.wp.com/likes/#blog_id=%2$d&amp;post_id=%3$d&amp;origin=%1$s://%4$s', $protocol, $blog_id, $post_id, $domain );
  512. $html = "<iframe class='admin-bar-likes-widget jetpack-likes-widget' scrolling='no' frameBorder='0' name='admin-bar-likes-widget' src='$src'></iframe>";
  513. $node = array(
  514. 'id' => 'admin-bar-likes-widget',
  515. 'meta' => array(
  516. 'html' => $html,
  517. ),
  518. );
  519. $wp_admin_bar->add_node( $node );
  520. }
  521. }
  522. /**
  523. * Callback to get the value for the jetpack_likes_enabled field.
  524. *
  525. * Warning: this behavior is somewhat complicated!
  526. * When the switch_like_status post_meta is unset, we follow the global setting in Sharing.
  527. * When it is set to 0, we disable likes on the post, regardless of the global setting.
  528. * When it is set to 1, we enable likes on the post, regardless of the global setting.
  529. *
  530. * @param array $post - post data we're checking.
  531. */
  532. function jetpack_post_likes_get_value( array $post ) {
  533. $post_likes_switched = get_post_meta( $post['id'], 'switch_like_status', true );
  534. /** This filter is documented in modules/jetpack-likes-settings.php */
  535. $sitewide_likes_enabled = (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) );
  536. // An empty string: post meta was not set, so go with the global setting.
  537. if ( '' === $post_likes_switched ) {
  538. return $sitewide_likes_enabled;
  539. } elseif ( '0' === $post_likes_switched ) { // User overrode the global setting to disable likes.
  540. return false;
  541. } elseif ( '1' === $post_likes_switched ) { // User overrode the global setting to enable likes.
  542. return true;
  543. }
  544. // No default fallback, let's stay explicit.
  545. }
  546. /**
  547. * Callback to set switch_like_status post_meta when jetpack_likes_enabled is updated.
  548. *
  549. * Warning: this behavior is somewhat complicated!
  550. * When the switch_like_status post_meta is unset, we follow the global setting in Sharing.
  551. * When it is set to 0, we disable likes on the post, regardless of the global setting.
  552. * When it is set to 1, we enable likes on the post, regardless of the global setting.
  553. *
  554. * @param bool $enable_post_likes - checks if post likes are enabled.
  555. * @param object $post_object - object containing post data.
  556. */
  557. function jetpack_post_likes_update_value( $enable_post_likes, $post_object ) {
  558. /** This filter is documented in modules/jetpack-likes-settings.php */
  559. $sitewide_likes_enabled = (bool) apply_filters( 'wpl_is_enabled_sitewide', ! get_option( 'disabled_likes' ) );
  560. $should_switch_status = $enable_post_likes !== $sitewide_likes_enabled;
  561. if ( $should_switch_status ) {
  562. // Set the meta to 0 if the user wants to disable likes, 1 if user wants to enable.
  563. $switch_like_status = ( $enable_post_likes ? 1 : 0 );
  564. return update_post_meta( $post_object->ID, 'switch_like_status', $switch_like_status );
  565. } else {
  566. // Unset the meta otherwise.
  567. return delete_post_meta( $post_object->ID, 'switch_like_status' );
  568. }
  569. }
  570. /**
  571. * Add Likes post_meta to the REST API Post response.
  572. *
  573. * @action rest_api_init
  574. * @uses register_rest_field
  575. * @link https://developer.wordpress.org/rest-api/extending-the-rest-api/modifying-responses/
  576. */
  577. function jetpack_post_likes_register_rest_field() {
  578. $post_types = get_post_types( array( 'public' => true ) );
  579. foreach ( $post_types as $post_type ) {
  580. register_rest_field(
  581. $post_type,
  582. 'jetpack_likes_enabled',
  583. array(
  584. 'get_callback' => 'jetpack_post_likes_get_value',
  585. 'update_callback' => 'jetpack_post_likes_update_value',
  586. 'schema' => array(
  587. 'description' => __( 'Are Likes enabled?', 'jetpack' ),
  588. 'type' => 'boolean',
  589. ),
  590. )
  591. );
  592. /**
  593. * Ensures all public internal post-types support `likes`
  594. * This feature support flag is used by the REST API and Gutenberg.
  595. */
  596. add_post_type_support( $post_type, 'jetpack-post-likes' );
  597. }
  598. }
  599. // Add Likes post_meta to the REST API Post response.
  600. add_action( 'rest_api_init', 'jetpack_post_likes_register_rest_field' );
  601. // Some CPTs (e.g. Jetpack portfolios and testimonials) get registered with
  602. // restapi_theme_init because they depend on theme support, so let's also hook to that.
  603. add_action( 'restapi_theme_init', 'jetpack_post_likes_register_rest_field', 20 );
  604. /**
  605. * Set the Likes and Sharing Gutenberg extension availability.
  606. */
  607. function jetpack_post_likes_set_extension_availability() {
  608. Jetpack_Gutenberg::set_extension_available( 'likes' );
  609. }
  610. add_action( 'jetpack_register_gutenberg_extensions', 'jetpack_post_likes_set_extension_availability' );
  611. Jetpack_Likes::init();