Index: src/wp-includes/post.php
===================================================================
--- src/wp-includes/post.php	(revision 36390)
+++ src/wp-includes/post.php	(working copy)
@@ -2132,7 +2132,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 sticked.
+		 *
+		 * @since 4.5.0
+		 *
+		 * @param int $post_id The ID of the post that was sticked.
+		 */
+		do_action( 'post_sticked', $post_id );
+	}
 }
 
 /**
@@ -2159,7 +2170,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 unsticked.
+		 *
+		 * @since 4.5.0
+		 *
+		 * @param int $post_id The ID of the post that was unsticked.
+		 */
+		do_action( 'post_unsticked', $post_id );
+	}
 }
 
 /**
Index: tests/phpunit/tests/post.php
===================================================================
--- tests/phpunit/tests/post.php	(revision 36390)
+++ tests/phpunit/tests/post.php	(working copy)
@@ -1182,6 +1182,47 @@
 	}
 
 	/**
+	 * 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.
+		$post = self::factory()->post->create_and_get( array(
+			'post_title' => 'Dummy post title',
+			'post_content' => 'Dummy post content',
+		) );
+
+		$this->assertFalse( is_sticky( $post->ID ) );
+
+		// Callback for testing hook.
+		$sticked_cb = function ( $post_id ) use ( $post ) {
+			update_option('_test_sticked_post_' . $post->ID, 'yes');
+		};
+
+		// Callback for testing hook.
+		$unsticked_cb = function ( $post_id ) use ( $post ) {
+			update_option( '_test_unsticked_post_' . $post->ID, 'yes');
+		};
+
+		// Hook callbacks.
+		add_action( 'post_sticked', $sticked_cb );
+		add_action( 'post_unsticked', $unsticked_cb );
+
+		stick_post( $post->ID );
+
+		$this->assertTrue( is_sticky( $post->ID ) );
+
+		unstick_post( $post->ID );
+
+		$this->assertFalse( is_sticky( $post->ID ) );
+
+		// Verify the hooks ran when sticking and unsticking the post.
+		$this->assertEquals('yes', get_option( '_test_sticked_post_' . $post->ID, false ) );
+		$this->assertEquals('yes', get_option( '_test_unsticked_post_' . $post->ID, false ) );
+	}
+
+	/**
 	 * If a post is updated without providing a post_name param,
 	 * a new slug should not be generated.
 	 *
