Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: sticky meta box #1282

Merged
merged 15 commits into from
Jan 24, 2025
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
131 changes: 131 additions & 0 deletions library/StickyPost/AddStickyCheckboxForPost.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?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
{
if (
!$this->wpService->currentUserCan('edit_post', $postId) ||
$this->wpService->checkAdminReferer(self::NONCE_ACTION, self::NONCE_NAME) === false
) {
die;
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;
}
57 changes: 57 additions & 0 deletions library/StickyPost/Helper/GetStickyOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?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
{
/**
* 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
{
$option = $this->wpService->getOption(
$this->getOptionKey($suffix),
[]
);

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

return $option;
}
}
Loading
Loading