calendar.php 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. /**
  3. * Server-side rendering of the `core/calendar` block.
  4. *
  5. * @package WordPress
  6. */
  7. /**
  8. * Renders the `core/calendar` block on server.
  9. *
  10. * @param array $attributes The block attributes.
  11. *
  12. * @return string Returns the block content.
  13. */
  14. function render_block_core_calendar( $attributes ) {
  15. global $monthnum, $year;
  16. // Calendar shouldn't be rendered
  17. // when there are no published posts on the site.
  18. if ( ! block_core_calendar_has_published_posts() ) {
  19. if ( is_user_logged_in() ) {
  20. return '<div>' . __( 'The calendar block is hidden because there are no published posts.' ) . '</div>';
  21. }
  22. return '';
  23. }
  24. $previous_monthnum = $monthnum;
  25. $previous_year = $year;
  26. if ( isset( $attributes['month'] ) && isset( $attributes['year'] ) ) {
  27. $permalink_structure = get_option( 'permalink_structure' );
  28. if (
  29. str_contains( $permalink_structure, '%monthnum%' ) &&
  30. str_contains( $permalink_structure, '%year%' )
  31. ) {
  32. // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
  33. $monthnum = $attributes['month'];
  34. // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
  35. $year = $attributes['year'];
  36. }
  37. }
  38. $wrapper_attributes = get_block_wrapper_attributes();
  39. $output = sprintf(
  40. '<div %1$s>%2$s</div>',
  41. $wrapper_attributes,
  42. get_calendar( true, false )
  43. );
  44. // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
  45. $monthnum = $previous_monthnum;
  46. // phpcs:ignore WordPress.WP.GlobalVariablesOverride.OverrideProhibited
  47. $year = $previous_year;
  48. return $output;
  49. }
  50. /**
  51. * Registers the `core/calendar` block on server.
  52. */
  53. function register_block_core_calendar() {
  54. register_block_type_from_metadata(
  55. __DIR__ . '/calendar',
  56. array(
  57. 'render_callback' => 'render_block_core_calendar',
  58. )
  59. );
  60. }
  61. add_action( 'init', 'register_block_core_calendar' );
  62. /**
  63. * Returns whether or not there are any published posts.
  64. *
  65. * Used to hide the calendar block when there are no published posts.
  66. * This compensates for a known Core bug: https://core.trac.wordpress.org/ticket/12016
  67. *
  68. * @return bool Has any published posts or not.
  69. */
  70. function block_core_calendar_has_published_posts() {
  71. // Multisite already has an option that stores the count of the published posts.
  72. // Let's use that for multisites.
  73. if ( is_multisite() ) {
  74. return 0 < (int) get_option( 'post_count' );
  75. }
  76. // On single sites we try our own cached option first.
  77. $has_published_posts = get_option( 'wp_calendar_block_has_published_posts', null );
  78. if ( null !== $has_published_posts ) {
  79. return (bool) $has_published_posts;
  80. }
  81. // No cache hit, let's update the cache and return the cached value.
  82. return block_core_calendar_update_has_published_posts();
  83. }
  84. /**
  85. * Queries the database for any published post and saves
  86. * a flag whether any published post exists or not.
  87. *
  88. * @return bool Has any published posts or not.
  89. */
  90. function block_core_calendar_update_has_published_posts() {
  91. global $wpdb;
  92. $has_published_posts = (bool) $wpdb->get_var( "SELECT 1 as test FROM {$wpdb->posts} WHERE post_type = 'post' AND post_status = 'publish' LIMIT 1" );
  93. update_option( 'wp_calendar_block_has_published_posts', $has_published_posts );
  94. return $has_published_posts;
  95. }
  96. // We only want to register these functions and actions when
  97. // we are on single sites. On multi sites we use `post_count` option.
  98. if ( ! is_multisite() ) {
  99. /**
  100. * Handler for updating the has published posts flag when a post is deleted.
  101. *
  102. * @param int $post_id Deleted post ID.
  103. */
  104. function block_core_calendar_update_has_published_post_on_delete( $post_id ) {
  105. $post = get_post( $post_id );
  106. if ( ! $post || 'publish' !== $post->post_status || 'post' !== $post->post_type ) {
  107. return;
  108. }
  109. block_core_calendar_update_has_published_posts();
  110. }
  111. /**
  112. * Handler for updating the has published posts flag when a post status changes.
  113. *
  114. * @param string $new_status The status the post is changing to.
  115. * @param string $old_status The status the post is changing from.
  116. * @param WP_Post $post Post object.
  117. */
  118. function block_core_calendar_update_has_published_post_on_transition_post_status( $new_status, $old_status, $post ) {
  119. if ( $new_status === $old_status ) {
  120. return;
  121. }
  122. if ( 'post' !== get_post_type( $post ) ) {
  123. return;
  124. }
  125. if ( 'publish' !== $new_status && 'publish' !== $old_status ) {
  126. return;
  127. }
  128. block_core_calendar_update_has_published_posts();
  129. }
  130. add_action( 'delete_post', 'block_core_calendar_update_has_published_post_on_delete' );
  131. add_action( 'transition_post_status', 'block_core_calendar_update_has_published_post_on_transition_post_status', 10, 3 );
  132. }