Skip to content

Commit

Permalink
Merge pull request #1282 from helsingborg-stad/feat/sticky-meta-box
Browse files Browse the repository at this point in the history
feat: sticky meta box
  • Loading branch information
NiclasNorin authored Jan 24, 2025
2 parents 34d564d + 0eac037 commit 12f0da9
Show file tree
Hide file tree
Showing 7 changed files with 369 additions and 5 deletions.
41 changes: 36 additions & 5 deletions library/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,11 @@ public function __construct(
*/
$this->setupComponentContextFilters();

/**
* Sticky posts
*/
$this->setupStickyPosts();

/**
* Login screen
*/
Expand Down Expand Up @@ -435,6 +440,25 @@ private function setUpBrokenLinksIntegration(): void
$redirect->addHooks();
}

/**
* Sets up the sticky posts feature.
*
* This method initializes the sticky posts feature by creating an instance of the
* StickyPosts class and passing
*/
private function setupStickyPosts(): void
{
$stickyPostConfig = new \Municipio\StickyPost\Config\StickyPostConfig();
$stickyPostHelper = new \Municipio\StickyPost\Helper\GetStickyOption(
$stickyPostConfig,
$this->wpService
);
(new \Municipio\StickyPost\AddStickyCheckboxForPost(
$stickyPostHelper,
$this->wpService
))->addHooks();
}

/**
* Set up the custom login screen.
*
Expand All @@ -445,7 +469,14 @@ private function setUpBrokenLinksIntegration(): void
private function setupLoginLogout(): void
{
//Needs setUser to be called before using the user object
$userHelper = new User($this->wpService, $this->acfService, new UserConfig(), new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService), new \Municipio\Helper\Term\Term($this->wpService, $this->acfService), new \Municipio\Helper\SiteSwitcher\SiteSwitcher($this->wpService, $this->acfService));
$userHelper = new User(
$this->wpService,
$this->acfService,
new UserConfig(),
new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService),
new \Municipio\Helper\Term\Term($this->wpService, $this->acfService),
new \Municipio\Helper\SiteSwitcher\SiteSwitcher($this->wpService, $this->acfService)
);

$filterAuthUrls = new \Municipio\Admin\Login\RelationalLoginLogourUrls($this->wpService);
$filterAuthUrls->addHooks();
Expand Down Expand Up @@ -486,8 +517,8 @@ private function setupUserGroupFeature(): void
// Setup dependencies
$userGroupRestrictionConfig = new \Municipio\Admin\Private\Config\UserGroupRestrictionConfig();
$userHelperConfig = new \Municipio\Helper\User\Config\UserConfig();
$userHelper = new \Municipio\Helper\User\User(

$userHelper = new \Municipio\Helper\User\User(
$this->wpService,
$this->acfService,
$userHelperConfig,
Expand Down Expand Up @@ -542,15 +573,15 @@ private function setupUserGroupFeature(): void
*/
private function setUpMiniOrangeIntegration(): void
{
$userHelper = new \Municipio\Helper\User\User(
$userHelper = new \Municipio\Helper\User\User(
$this->wpService,
$this->acfService,
new \Municipio\Helper\User\Config\UserConfig(),
new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService),
new \Municipio\Helper\Term\Term($this->wpService, $this->acfService),
new \Municipio\Helper\SiteSwitcher\SiteSwitcher($this->wpService, $this->acfService)
);

$termHelper = new \Municipio\Helper\Term\Term($this->wpService, $this->acfService);
$userGroupConfig = new \Municipio\UserGroup\Config\UserGroupConfig($this->wpService);
$config = new \Municipio\Integrations\MiniOrange\Config\MiniOrangeConfig($this->wpService);
Expand Down
132 changes: 132 additions & 0 deletions library/StickyPost/AddStickyCheckboxForPost.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

namespace Municipio\StickyPost;

use Municipio\HooksRegistrar\Hookable;
use Municipio\StickyPost\Helper\GetStickyOption as GetStickyOptionHelper;
use WpService\Contracts\__;
use WpService\Contracts\AddAction;
use WpService\Contracts\CheckAdminReferer;
use WpService\Contracts\Checked;
use WpService\Contracts\CurrentUserCan;
use WpService\Contracts\GetOption;
use WpService\Contracts\GetPostType;
use WpService\Contracts\UpdateOption;
use WpService\Contracts\WpNonceField;

/**
* Represents a AddStickyCheckboxForPost class.
*
* This class is responsible for adding a sticky checkbox for private posts.
*/
class AddStickyCheckboxForPost implements Hookable
{
private const NONCE_ACTION = 'municipio_sticky_post_update';
private const NONCE_NAME = '_municipio_sticky_post_nonce';

/**
* Constructor for the AddStickyCheckboxForPost class.
*/
public function __construct(
private GetStickyOptionHelper $getStickyOptionHelper,
private AddAction&CurrentUserCan&Checked&__&GetOption&UpdateOption&GetPostType&WpNonceField&CheckAdminReferer $wpService
) {
}

/**
* Adds hooks for the StickyPost class.
*
* This method adds hooks to display and save the sticky checkbox value for both posts and attachments.
*
* @return void
*/
public function addHooks(): void
{
$this->wpService->addAction('post_submitbox_misc_actions', array($this, 'addStickyCheckbox'), 10);
$this->wpService->addAction('attachment_submitbox_misc_actions', array($this, 'addStickyCheckbox'), 10);
$this->wpService->addAction('save_post', array($this, 'saveStickyCheckboxValue'));
$this->wpService->addAction('edit_attachment', array($this, 'saveStickyCheckboxValue'));
}

/**
* Saves the value of the sticky checkbox for a private post.
*
* @param int $postId The ID of the post.
* @return void
*/
public function saveStickyCheckboxValue(int $postId): void
{
// TODO: Fix nonce check
// Check if failing in gutenberg is caused by nonce since nonce field isnt created.
if (
!$this->wpService->currentUserCan('edit_post', $postId)
// $this->wpService->checkAdminReferer(self::NONCE_ACTION, self::NONCE_NAME) === false
) {
return;
}

$postType = $this->wpService->getPostType($postId);
$optionName = $this->getStickyOptionHelper->getOptionKey($postType);
$stickyOption = $this->getStickyOptionHelper->getOption($postType);

// phpcs:ignore WordPress.Security.NonceVerification.Missing
if (isset($_POST[$optionName])) {
$stickyOption[$postId] = $postId;
} else {
unset($stickyOption[$postId]);
}

$this->wpService->updateOption($optionName, $stickyOption);
}

/**
* Adds a sticky checkbox for private posts.
*
* This method adds a sticky checkbox for private posts. It checks if the current user has the capability to
* edit the post. If not, the method returns without performing any action. Otherwise, it retrieves the
* sticky post meta value for the post and determines whether the checkbox should be checked or not.
* Finally, it renders the sticky checkbox with the provided checked value.
*
* @return void
*/
public function addStickyCheckbox(): void
{
global $post;

if (
!isset($post) ||
!$this->wpService->currentUserCan('edit_post', $post->ID) ||
empty($post->post_type)
) {
return;
}

$stickyOption = $this->getStickyOptionHelper->getOption($post->post_type);
$checked = $this->wpService->checked(array_key_exists($post->ID, $stickyOption), true, false);

$this->renderStickyCheckbox($checked, $post->post_type);
}

/**
* Renders a sticky checkbox for a private post.
*
* @param string $checked
* @return void
*/
private function renderStickyCheckbox(string $checked, string $postType): void
{
echo sprintf(
'
<div class="misc-pub-section misc-pub-sticky">
<label><input type="checkbox" name="%s" value="true" %s> %s</label>
',
$this->getStickyOptionHelper->getOptionKey($postType),
$checked,
$this->wpService->__('Make this post sticky', 'municipio')
);

$this->wpService->wpNonceField(self::NONCE_ACTION, self::NONCE_NAME, true, true);

echo '</div>';
}
}
25 changes: 25 additions & 0 deletions library/StickyPost/Config/StickyPostConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Municipio\StickyPost\Config;

/**
* StickyPostConfig class.
*
* Represents the configuration for sticky posts in the theme.
* Implements the StickyPostConfigInterface.
*
*/
class StickyPostConfig implements StickyPostConfigInterface
{
private string $prefix = 'sticky_post';

/**
* Get the prefix for the option key.
*
* @return string
*/
public function getOptionKeyPrefix(): string
{
return $this->prefix;
}
}
26 changes: 26 additions & 0 deletions library/StickyPost/Config/StickyPostConfig.test.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Municipio\StickyPost\Config;

use PHPUnit\Framework\TestCase;

class StickyPostConfigTest extends TestCase
{
/**
* @testdox class can be instantiated
*/
public function testCanBeInstantiated()
{
$stickyPostConfig = new StickyPostConfig();
$this->assertInstanceOf(StickyPostConfig::class, $stickyPostConfig);
}

/**
* @testdox getOptionKeyPrefix returns string
*/
public function testGetOptionKeyPrefixReturnsString()
{
$stickyPostConfig = new StickyPostConfig();
$this->assertIsString($stickyPostConfig->getOptionKeyPrefix());
}
}
18 changes: 18 additions & 0 deletions library/StickyPost/Config/StickyPostConfigInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Municipio\StickyPost\Config;

/**
* Represents a StickyPostConfigInterface interface.
*
* This interface is responsible for defining the methods that a sticky post configuration class must implement.
*/
interface StickyPostConfigInterface
{
/**
* Get the prefix for the option key.
*
* @return string
*/
public function getOptionKeyPrefix(): string;
}
67 changes: 67 additions & 0 deletions library/StickyPost/Helper/GetStickyOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php

namespace Municipio\StickyPost\Helper;

use Municipio\StickyPost\Config\StickyPostConfigInterface;
use WpService\Contracts\GetOption;

/**
* Represents a GetStickyOption class.
*
* This class is responsible for retrieving the sticky option for a given post type.
*/
class GetStickyOption
{
private static array $optionsCache = [];

/**
* Constructor for the GetStickyOption class.
*
* @param StickyPostConfigInterface $stickyPostConfig The sticky post configuration.
* @param GetOption $wpService The WP service.
*/
public function __construct(
private StickyPostConfigInterface $stickyPostConfig,
private GetOption $wpService
) {
}

/**
* Returns the option key for a given suffix.
*
* @param string $suffix The suffix to append to the option key.
* @return string The option key.
*/
public function getOptionKey(string $suffix): string
{
return $this->stickyPostConfig->getOptionKeyPrefix() . '_' . $suffix;
}

/**
* Retrieves the sticky option for a given post type.
*
* @param string $postType The post type.
* @return array The sticky option for the post type.
*/
public function getOption(string $suffix): array
{
$key = $this->getOptionKey($suffix);

if (isset(self::$optionsCache[$key])) {
return self::$optionsCache[$key];
}

$option = $this->wpService->getOption(
$this->getOptionKey($suffix),
[]
);

if (!is_array($option)) {
$option = [];
}

self::$optionsCache[$key] = $option;

return $option;
}
}
Loading

0 comments on commit 12f0da9

Please sign in to comment.