Skip to content

Commit 13473b1

Browse files
committed
Merge branch 'release/2.6.2'
2 parents fc25072 + 17416ed commit 13473b1

File tree

14 files changed

+713
-369
lines changed

14 files changed

+713
-369
lines changed

CHANGELOG.md

Lines changed: 163 additions & 157 deletions
Large diffs are not rendered by default.

bin/update-changelog.js

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
const fs = require( 'fs' );
2+
3+
// Read the current version number from package.json
4+
const newVersion = process.argv[ 2 ];
5+
// --- Format Date as MM/DD/YYYY ---
6+
const today = new Date();
7+
const month = String( today.getMonth() + 1 ).padStart( 2, '0' ); // Months are 0-indexed
8+
const day = String( today.getDate() ).padStart( 2, '0' );
9+
const year = today.getFullYear();
10+
const releaseDate = `${ month }/${ day }/${ year }`; // Format as MM/DD/YYYY
11+
// --- End Date Formatting ---
12+
13+
if ( ! newVersion ) {
14+
console.error( 'Please provide the new version number as an argument.' );
15+
process.exit( 1 );
16+
}
17+
18+
// Check if --verbose or -v is passed
19+
const isVerbose =
20+
process.argv.includes( '--verbose' ) || process.argv.includes( '-v' );
21+
22+
// Read and process CHANGELOG.md
23+
const changelogFilePath = 'CHANGELOG.md';
24+
const readmeFilePath = 'readme.txt';
25+
26+
let changelogContent = fs.readFileSync( changelogFilePath, 'utf8' );
27+
28+
// Improved pattern to capture unreleased changes
29+
const unreleasedPattern = /^## Unreleased\s([\s\S]*?)(?=\n## |\n$)/m;
30+
const unreleasedMatch = changelogContent.match( unreleasedPattern );
31+
32+
if ( ! unreleasedMatch ) {
33+
console.error( 'No unreleased changes found in CHANGELOG.md.' );
34+
process.exit( 1 );
35+
}
36+
37+
const unreleasedChanges = unreleasedMatch[ 1 ]
38+
.trim()
39+
.split( '\n' )
40+
.filter( ( line ) => line.trim() !== '' );
41+
const changeCount = unreleasedChanges.length;
42+
43+
// Format unreleased changes into a numbered list if verbose option is used
44+
if ( isVerbose ) {
45+
const formattedConsoleChanges = unreleasedChanges
46+
.map(
47+
( change, index ) =>
48+
`${ index + 1 }. ${ change.replace( /^\-\s*/, '' ) }`
49+
)
50+
.join( '\n' );
51+
console.log( 'Unreleased Changes:\n' + formattedConsoleChanges );
52+
}
53+
54+
// --- Format for CHANGELOG.md ---
55+
// The captured lines already have the correct '- ' format.
56+
// Just join them together.
57+
const formattedChangelogChanges = unreleasedChanges.join( '\n' );
58+
59+
// Update CHANGELOG.md with new version using the original lines
60+
const updatedChangelog = changelogContent.replace(
61+
unreleasedPattern,
62+
`## Unreleased\n\n## v${ newVersion } - ${ releaseDate }\n\n${ formattedChangelogChanges }` // Use the joined original lines
63+
);
64+
65+
fs.writeFileSync( changelogFilePath, updatedChangelog, 'utf8' );
66+
67+
// --- Format for readme.txt ---
68+
const readmeContent = fs.readFileSync( readmeFilePath, 'utf8' );
69+
70+
// Pattern to find the changelog header and any immediate following whitespace
71+
const changelogPattern = /(== Changelog ==\s*)/s;
72+
73+
if ( !changelogPattern.test( readmeContent ) ) {
74+
console.error( 'Could not find "== Changelog ==" section in readme.txt' );
75+
process.exit( 1 );
76+
}
77+
78+
// Format unreleased changes: replace '- ' with '* '
79+
const formattedReadmeChanges = unreleasedChanges
80+
.map( ( change ) => `* ${ change.replace( /^\-\s*/, '' ).trim() }` ) // Replace '- ...' with '* ...' and trim potential leading space after replace
81+
.join( '\n' );
82+
83+
// Create the new version entry using '*'
84+
const newReadmeVersionEntry = `= v${ newVersion } - ${ releaseDate } =\n\n${ formattedReadmeChanges }\n\n`;
85+
86+
// Replace the matched header and whitespace with itself followed by the new entry
87+
const newReadmeContent = readmeContent.replace(
88+
changelogPattern,
89+
`$1${ newReadmeVersionEntry }`
90+
);
91+
92+
// Remove the debugging code if it's no longer needed, or keep it for now
93+
// --- Debugging Start ---
94+
console.log( '--- Debug readme.txt ---' );
95+
console.log( 'Pattern:', changelogPattern );
96+
const matchResult = readmeContent.match( changelogPattern );
97+
console.log( 'Match found:', matchResult ? 'Yes' : 'No' );
98+
if ( matchResult ) {
99+
console.log( 'Matched text ($1):', JSON.stringify( matchResult[ 1 ] ) );
100+
}
101+
console.log( 'New entry:\n', newReadmeVersionEntry );
102+
console.log( '--- Attempting to write new readme content (first 500 chars): ---' );
103+
console.log( newReadmeContent.substring( 0, 500 ) );
104+
console.log( '--- End Debug ---' );
105+
// --- Debugging End ---
106+
107+
fs.writeFileSync( readmeFilePath, newReadmeContent.trim(), 'utf8' );
108+
109+
// Output the count of changes
110+
console.log(
111+
`Changelog updated successfully with ${ changeCount } change(s).`
112+
);

bin/update-versions.js

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/**
2+
* Replaces version numbers in files.
3+
*
4+
* Usage:
5+
* node replace-versions.js <version>
6+
*
7+
* Parameters:
8+
* <version> The version number to replace.
9+
* --dry-run Prints the files that would be modified without actually modifying them.
10+
* --plugin Replaces the version in plugin files.
11+
* --docblock Replaces the version in docblocks.
12+
* --comment Replaces the version in comments.
13+
* --all Replaces the version in all files.
14+
*/
15+
16+
const fs = require('fs');
17+
const path = require('path');
18+
const glob = require('glob');
19+
const minimist = require('minimist');
20+
21+
const argv = minimist(process.argv.slice(2));
22+
23+
const version = argv._[0];
24+
25+
if (!version) {
26+
console.error('Please provide a version number.');
27+
process.exit(1);
28+
}
29+
30+
const dryRun = argv['dry-run'];
31+
32+
let replaceType = 'all';
33+
34+
if (argv['plugin']) {
35+
replaceType = 'plugin';
36+
} else if (argv['docblock']) {
37+
replaceType = 'docblock';
38+
}
39+
40+
const excludedDirs = [
41+
'node_modules/**',
42+
'vendor/**',
43+
'vendor-prefixed/**',
44+
'bin/**',
45+
];
46+
47+
const versionPatterns = [
48+
// Plugin file header.
49+
{
50+
regex: /^([\t ]*\*[\t ]*Version:[\t ]*)(.*)/gm,
51+
replacement: (newVersion) => `$1${newVersion}`,
52+
},
53+
// Plugin main class version.
54+
{
55+
regex: /^(.*public[\t ]+static[\t ]+\$VER[\t ]*=[\t ]*['"])(.*)(['"];\s*)$/gm,
56+
replacement: (newVersion) => `$1${newVersion}$3`,
57+
},
58+
// Plugin config array.
59+
{
60+
regex: /^([\t ]*'version'[\t ]*=>[\t ]*['"])(.*)(['"],)$/gm,
61+
replacement: (newVersion) => `$1${newVersion}$3`,
62+
},
63+
// Plugin readme.
64+
{
65+
regex: /^(Stable tag:[\t ]*)(.*)/gm,
66+
replacement: (newVersion) => `$1${newVersion}`,
67+
},
68+
// Plugin composer & package json.
69+
{
70+
regex: /(\s*"version":\s*")(\d+\.\d+\.\d+)(")/gm,
71+
replacement: (newVersion) => `$1${newVersion}$3`,
72+
},
73+
];
74+
75+
const docblockPatterns = [
76+
{
77+
// Only match if the version is currently X.X.X exactly (the string "@deprecated X.X.X").
78+
regex: /((@deprecated|@since|@version)\s+)X.X.X/gm,
79+
replacement: (newVersion) => (_match, tag) => {
80+
return `${tag}${newVersion}`;
81+
},
82+
},
83+
];
84+
85+
const commentPatterns = [
86+
{
87+
// Match // single line comments with X.X.X
88+
regex: /(\/\/.*\s+)X.X.X/gm,
89+
replacement: (newVersion) => (_match, prefix) => {
90+
return `${prefix}${newVersion}`;
91+
},
92+
},
93+
{
94+
// Match /* single line comments with X.X.X */
95+
regex: /(\/\*.*\s+)X.X.X/gm,
96+
replacement: (newVersion) => (_match, prefix) => {
97+
return `${prefix}${newVersion}`;
98+
},
99+
},
100+
{
101+
// Match /** multi line comments (start with *\s)
102+
regex: /(\s+\*.*\s+)X.X.X/gm,
103+
replacement: (newVersion) => (_match, prefix) => {
104+
return `${prefix}${newVersion}`;
105+
},
106+
},
107+
];
108+
109+
/**
110+
* Update version in specified files with the given patterns.
111+
*
112+
* @param {string} filePath - Path to the file.
113+
* @param {string} newVersion - The new version number.
114+
* @param {boolean} dryRun - Indicate if this is a dry run.
115+
* @param {Array} patterns - Array of regex patterns to match and replace.
116+
*/
117+
function updateVersionInFile(filePath, newVersion, dryRun, patterns) {
118+
if (fs.existsSync(filePath)) {
119+
const contents = fs.readFileSync(filePath, 'utf8');
120+
let newContents = contents;
121+
122+
patterns.forEach((pattern) => {
123+
newContents = newContents.replace(
124+
pattern.regex,
125+
pattern.replacement(newVersion)
126+
);
127+
});
128+
129+
if (newContents !== contents) {
130+
if (dryRun) {
131+
console.log(`${filePath}:`);
132+
console.log(newContents);
133+
} else {
134+
fs.writeFileSync(filePath, newContents, 'utf8');
135+
}
136+
}
137+
} else {
138+
console.log(`No file found at ${filePath}`);
139+
}
140+
}
141+
142+
if (replaceType === 'all' || replaceType === 'plugin') {
143+
const pluginSlug = path.basename(process.cwd());
144+
const pluginFile = process.cwd() + '/' + pluginSlug + '.php';
145+
const boostrapFile = process.cwd() + '/bootstrap.php';
146+
const readmeFile = process.cwd() + '/readme.txt';
147+
const packageJsonFile = process.cwd() + '/' + 'package.json';
148+
const composerJsonFile = process.cwd() + '/' + 'composer.json';
149+
150+
if (fs.existsSync(pluginFile)) {
151+
updateVersionInFile(pluginFile, version, dryRun, versionPatterns);
152+
}
153+
154+
if (fs.existsSync(boostrapFile)) {
155+
updateVersionInFile(boostrapFile, version, dryRun, versionPatterns);
156+
}
157+
158+
if (fs.existsSync(readmeFile)) {
159+
updateVersionInFile(readmeFile, version, dryRun, versionPatterns);
160+
}
161+
162+
if (fs.existsSync(packageJsonFile)) {
163+
updateVersionInFile(packageJsonFile, version, dryRun, versionPatterns);
164+
}
165+
166+
if (fs.existsSync(composerJsonFile)) {
167+
updateVersionInFile(composerJsonFile, version, dryRun, versionPatterns);
168+
}
169+
}
170+
171+
if (
172+
replaceType === 'all' ||
173+
replaceType === 'docblock' ||
174+
replaceType === 'comment'
175+
) {
176+
const files = glob.sync('**/*.php', { ignore: excludedDirs });
177+
178+
// One loop reduces the number of file system calls.
179+
files.forEach((file) => {
180+
if (replaceType === 'all' || replaceType === 'docblock') {
181+
updateVersionInFile(file, version, dryRun, docblockPatterns);
182+
}
183+
184+
if (replaceType === 'all' || replaceType === 'comment') {
185+
updateVersionInFile(file, version, dryRun, commentPatterns);
186+
}
187+
});
188+
}

classes/Controllers/Frontend/Restrictions/PostContent.php

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@ public function filter_the_content_if_restricted( $content ) {
9898
return $content;
9999
}
100100

101+
/**
102+
* Prevent the default restriction message from being shown by returning a custom
103+
* message or content.
104+
*
105+
* @param null|string $pre_restrict_content The content to display.
106+
* @param string $content The content.
107+
* @param \ContentControl\Models\Restriction $restriction The restriction.
108+
*
109+
* @return string
110+
*/
111+
$pre_restrict_content = apply_filters( 'content_control/pre_restrict_content', null, $content, $restriction );
112+
113+
if ( null !== $pre_restrict_content ) {
114+
return $pre_restrict_content;
115+
}
116+
101117
$message = \ContentControl\get_default_denial_message();
102118

103119
/**
@@ -118,8 +134,8 @@ public function filter_the_content_if_restricted( $content ) {
118134
/**
119135
* Filter the message to display when a post is restricted.
120136
*
121-
* @param string $message Message to display.
122-
* @param object $restriction Restriction object.
137+
* @param string $message Message to display.
138+
* @param \ContentControl\Models\Restriction $restriction The restriction.
123139
*
124140
* @return string
125141
*/
@@ -155,12 +171,27 @@ public function filter_the_excerpt_if_restricted( $post_excerpt, $post = null )
155171
return $post_excerpt;
156172
}
157173

158-
$restriction = get_applicable_restriction();
174+
$restriction = get_applicable_restriction( $post->ID );
159175

160176
if ( false === $restriction ) {
161177
return $post_excerpt;
162178
}
163179

180+
/**
181+
* Filter to bypass the default restriction message for excerpts.
182+
*
183+
* @since 2.0.0
184+
*
185+
* @param null|string $pre_excerpt Return a non-null value to bypass.
186+
* @param string $post_excerpt The original excerpt.
187+
* @param \ContentControl\Models\Restriction $restriction The restriction object.
188+
*/
189+
$pre_excerpt = apply_filters( 'content_control/pre_restrict_excerpt', null, $post_excerpt, $restriction );
190+
191+
if ( null !== $pre_excerpt ) {
192+
return $pre_excerpt;
193+
}
194+
164195
/**
165196
* Filter the excerpt to display when a post is restricted.
166197
*

classes/Controllers/Shortcodes.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,14 @@ public function content_control( $atts, $content = '' ) {
9393

9494
$classes = implode( ' ', $classes );
9595

96-
return sprintf( $container, esc_attr( $classes ), do_shortcode( $content ), do_shortcode( $atts['message'] ) );
96+
return sprintf(
97+
$container,
98+
esc_attr( $classes ),
99+
// Sanitize the content output, allowing safe HTML and processed shortcodes.
100+
wp_kses_post( do_shortcode( $content ) ),
101+
// Sanitize the message output, allowing safe HTML and processed shortcodes.
102+
wp_kses_post( do_shortcode( $atts['message'] ) )
103+
);
97104
}
98105

99106
/**

0 commit comments

Comments
 (0)