Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .distignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,12 @@ LICENSE.md
license.txt
phpcs.xml.dist
phpunit.xml.dist
phpstan.neon.dist
README.md
package.json
package-lock.json
node_modules
src
webpack.config.js
.eslintrc.js
.prettierrc.js
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: [ 'plugin:@wordpress/eslint-plugin/recommended' ],
globals: {
jQuery: 'readonly',
},
};
11 changes: 11 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,14 @@ vendor/

logs
*.log

############
## Build artifacts
############

*.map
*.asset.php
.build-entry.js
.build-script.js
.backup-source.js
.backup-source.css
21 changes: 21 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,27 @@ It is recommended to run integration tests and PHPCodeSniffer locally before com
* `vendor/bin/phpunit`: Run the integration tests.
* `vendor/bin/phpcs`: Check against the WordPress Coding Standards.

### JavaScript and CSS Build Pipeline

This plugin uses [@wordpress/scripts](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-scripts/) for building, linting, and minifying JavaScript and CSS assets. Both source and minified versions are located in `wp-multi-network/assets/`.

To work with JavaScript and CSS:

* `npm install`: Install Node.js dependencies (Node.js 20+ required)
* `npm run build`: Build minified production-ready assets from source files
* `npm run start`: Start development mode with file watching and hot reload
* `npm run lint:js`: Lint JavaScript files
* `npm run lint:css`: Lint CSS files
* `npm run format`: Auto-format JavaScript and CSS files

The asset structure:
* **Source files** (edit these): `wp-multi-network.js`, `wp-multi-network.css`, `wp-multi-network-rtl.css` (unminified, for debugging)
* **Minified files** (auto-generated): `wp-multi-network.min.js`, `wp-multi-network.min.css`, `wp-multi-network-rtl.min.css` (production)

The plugin automatically loads source files when `WP_SCRIPT_DEBUG` is enabled, otherwise it loads minified versions.

**Important:** Edit the non-minified source files in `wp-multi-network/assets/`. The minified `.min.js` and `.min.css` files are automatically generated by the build process and should not be edited directly.

### Writing Integration Tests

* Integration tests go into the `tests/integration/tests` directory.
Expand Down
28 changes: 28 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"name": "wp-multi-network",
"version": "2.7.0",
"description": "A Network Management Interface for global administrators in WordPress Multisite installations",
"private": true,
"scripts": {
"build": "npm run backup-source && wp-scripts build && npm run rename-assets && npm run restore-source && npm run generate-rtl-source && npm run cleanup-assets",
"backup-source": "cp wp-multi-network/assets/js/wp-multi-network.js .backup-source.js && cp wp-multi-network/assets/css/wp-multi-network.css .backup-source.css",
"restore-source": "mv .backup-source.js wp-multi-network/assets/js/wp-multi-network.js && mv .backup-source.css wp-multi-network/assets/css/wp-multi-network.css",
"rename-assets": "mv wp-multi-network/assets/css/style-wp-multi-network.min.css wp-multi-network/assets/css/wp-multi-network.min.css 2>/dev/null || true && mv wp-multi-network/assets/css/style-wp-multi-network.min-rtl.css wp-multi-network/assets/css/wp-multi-network-rtl.min.css 2>/dev/null || true",
"generate-rtl-source": "npx rtlcss wp-multi-network/assets/css/wp-multi-network.css wp-multi-network/assets/css/wp-multi-network-rtl.css",
"cleanup-assets": "rm -f wp-multi-network/assets/js/*.asset.php",
"start": "wp-scripts start",
"lint:js": "wp-scripts lint-js wp-multi-network/assets/js/",
"lint:css": "wp-scripts lint-style wp-multi-network/assets/css/",
"format": "wp-scripts format wp-multi-network/assets/",
"check-engines": "wp-scripts check-engines",
"check-licenses": "wp-scripts check-licenses"
},
"devDependencies": {
"@babel/runtime": "^7.28.4",
"@wordpress/scripts": "^28.0.0"
},
"engines": {
"node": ">=20.0.0",
"npm": ">=10.0.0"
}
}
63 changes: 63 additions & 0 deletions webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* Custom Webpack Configuration for WP Multi Network
*
* This configuration extends @wordpress/scripts default webpack config
* to customize the output location and naming of built assets.
*
* NOTE: Due to how webpack handles CSS extraction from JavaScript imports,
* the CSS files are generated with auto-generated chunk names that include
* a 'style-' prefix (e.g., 'style-wp-multi-network.css'). To maintain
* backward compatibility with the existing plugin structure, we use a
* post-build rename script (see package.json 'rename-assets') to rename
* these files to match the expected names ('wp-multi-network.css').
*
* @see https://webpack.js.org/configuration/
*/

const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
const RtlCssPlugin = require( 'rtlcss-webpack-plugin' );
const path = require( 'path' );

/**
* Helper function to generate CSS filename based on chunk name
*
* @param {Object} pathData - Webpack path data object
* @param {string} suffix - Optional suffix for the filename (e.g., '-rtl')
* @return {string} The CSS filename
*/
function getCssFilename( pathData, suffix = '' ) {
if ( pathData.chunk && pathData.chunk.name ) {
// The chunk name includes '.min', so we just add the suffix and extension
return 'css/' + pathData.chunk.name + suffix + '.css';
}
return 'css/[name]' + suffix + '.css';
}

module.exports = {
...defaultConfig,
entry: {
'wp-multi-network.min': path.resolve( process.cwd(), '.build-script.js' ),
},
output: {
path: path.resolve( process.cwd(), 'wp-multi-network/assets' ),
filename: 'js/[name].js',
},
plugins: [
// Remove default CSS plugins and replace with custom configuration
// to place CSS files in the css/ subdirectory with proper naming.
// @wordpress/scripts generates CSS chunks with auto-generated names
// (e.g., 'style-wp-multi-network') which we need to customize.
...defaultConfig.plugins.filter(
( plugin ) =>
! ( plugin instanceof MiniCssExtractPlugin ) &&
! ( plugin instanceof RtlCssPlugin )
),
new MiniCssExtractPlugin( {
filename: ( pathData ) => getCssFilename( pathData ),
} ),
new RtlCssPlugin( {
filename: ( pathData ) => getCssFilename( pathData, '-rtl' ),
} ),
],
};
156 changes: 156 additions & 0 deletions wp-multi-network/assets/css/wp-multi-network-rtl.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
th.column-title {
width: 35%;
}
th.column-path {
width: 15%;
}
th.column-blogs {
width: 10%;
}
td.column-domain {
white-space: nowrap;
overflow: hidden;
}

.edit-network label span.scheme {
display: inline-block;
}

.edit-network .form-field label input[type="text"] {
width: 50%;
display: inline-block;
}

#poststuff #wpmn-edit-network-assign-sites .inside {
margin: 0;
padding: 0;
}

#wpmn-edit-network-publish .submitbox,
#wpmn-move-site-publish .submitbox {
margin: 10px -12px -12px;
}

#wpmn-edit-network-publish #major-publishing-actions,
#wpmn-move-site-publish #major-publishing-actions {
margin-top: 10px;
}

#misc-publishing-actions #network:before,
#misc-publishing-actions #sites:before {
font: normal 20px/1 dashicons;
speak: none;
display: inline-block;
padding: 0 0 0 2px;
top: 0;
right: -1px;
position: relative;
vertical-align: top;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-decoration: none !important;
}

#misc-publishing-actions #network:before {
content: '\f319';
}

#misc-publishing-actions #sites:before {
content: '\f325';
}

table.widefat.move-site,
table.widefat.assign-sites {
border: none;
box-shadow: none;
}

table.move-site thead th,
table.assign-sites thead th {
text-align: center;
font-size: 13px;
font-weight: 600;
background: #f4f4f4;
}

.networks tbody td,
.networks tbody th {
-webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .1);
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, .1);
padding: 10px 9px;
}

.networks .current th.check-column {
border-right: 4px solid #00a0d2;
}

.networks .current td,
.networks .current th {
background-color: #f7fcfe;
padding: 10px 9px;
}

table.assign-sites select[multiple] {
width: 100%;
height: 80px !important;
margin: 0;
}

table.assign-sites .button {
margin: 0 5px;
width: 35%;
height: 80px;
}

table.assign-sites td.column-actions {
width: 16%;
padding: 8px 0;
}

table.assign-sites td.column-actions .assign {
float: right;
content: "\f341";
}

table.assign-sites td.column-actions .unassign {
float: left;
}

table.assign-sites td.column-available {
padding-left: 0;
}

table.assign-sites td.column-assigned {
padding-right: 0;
}
table.assign-sites td.column-available,
table.assign-sites td.column-assigned {
width: 42%;
}

table.assign-sites td.column-assigned {
text-align: left;
}

div.network-delete {
background: #fff;
border-right: 4px solid #dc3232;
-webkit-box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
margin: 5px 0 2px;
padding: 1px 12px;
}

div.network-delete p {
margin: 0.5em 0;
padding: 2px;
}

ul.delete-sites {
list-style: square;
margin: 10px 20px;
}

ul.delete-sites li {
margin: 0;
}
1 change: 1 addition & 0 deletions wp-multi-network/assets/css/wp-multi-network.min-rtl.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions wp-multi-network/assets/css/wp-multi-network.min.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading