Index: src/wp-includes/post.php
===================================================================
--- src/wp-includes/post.php	(revision 37640)
+++ src/wp-includes/post.php	(working copy)
@@ -2169,7 +2169,18 @@
 	if ( ! in_array($post_id, $stickies) )
 		$stickies[] = $post_id;
 
-	update_option('sticky_posts', $stickies);
+	$updated = update_option('sticky_posts', $stickies);
+
+	if ( $updated ) {
+		/**
+		 * Fires after a post is successfully stuck.
+		 *
+		 * @since 4.6.0
+		 *
+		 * @param int $post_id The ID of the post that was stuck.
+		 */
+		do_action( 'post_stuck', $post_id );
+	}
 }
 
 /**
@@ -2196,7 +2207,18 @@
 
 	array_splice($stickies, $offset, 1);
 
-	update_option('sticky_posts', $stickies);
+	$updated = update_option('sticky_posts', $stickies);
+
+	if ( $updated ) {
+		/**
+		 * Fires after a post is successfully unstuck.
+		 *
+		 * @since 4.6.0
+		 *
+		 * @param int $post_id The ID of the post that was unstuck.
+		 */
+		do_action( 'post_unstuck', $post_id );
+	}
 }
 
 /**
Index: tests/phpunit/tests/post.php
===================================================================
--- tests/phpunit/tests/post.php	(revision 37640)
+++ tests/phpunit/tests/post.php	(working copy)
@@ -1182,6 +1182,51 @@
 	}
 
 	/**
+	 * Test that hooks are fired for sticking and unsticking a post.
+	 *
+	 * @ticket 35600
+	 */
+	function test_post_stick_and_unstick_fire_actions() {
+		// Create a dummy post.
+		$sticky_test_post = self::factory()->post->create_and_get( array(
+			'post_title' => 'Dummy post title',
+			'post_content' => 'Dummy post content',
+		) );
+
+		$this->assertFalse( is_sticky( $sticky_test_post->ID ) );
+
+		// Hook callbacks.
+		add_action( 'post_stuck', array( $this, 'stuck_callback' ) );
+		add_action( 'post_unstuck', array( $this, 'unstuck_callback' ) );
+
+		stick_post( $sticky_test_post->ID );
+
+		$this->assertTrue( is_sticky( $sticky_test_post->ID ) );
+
+		unstick_post( $sticky_test_post->ID );
+
+		$this->assertFalse( is_sticky( $sticky_test_post->ID ) );
+
+		// Verify the hooks ran when sticking and unsticking the post.
+		$this->assertEquals( 'yes', get_option( '_test_sticked_post_' . $sticky_test_post->ID, false ) );
+		$this->assertEquals( 'yes', get_option( '_test_unsticked_post_' . $sticky_test_post->ID, false ) );
+	}
+
+	/**
+	 * Helper for `test_post_stick_and_unstick_fire_actions`.
+	 */
+	function stuck_callback( $post_id ) {
+		update_option( '_test_sticked_post_' . $post_id, 'yes' );
+	}
+
+	/**
+	 * Helper for `test_post_stick_and_unstick_fire_actions`.
+	 */
+	function unstuck_callback( $post_id ) {
+		update_option( '_test_unsticked_post_' . $post_id, 'yes' );
+	}
+
+	/**
 	 * If a post is updated without providing a post_name param,
 	 * a new slug should not be generated.
 	 *
